package ext.tianma.part.report.searchAPL.service;

import com.ptc.core.lwc.server.LWCNormalizedObject;
import com.ptc.core.meta.common.DataTypesUtility;
import ext.com.iba.IBAUtil;
import ext.generic.erp.common.CommonPDMUtil;
import ext.tianma.bom.expand.service.MaterielService;
import ext.tianma.bom.service.MaterialReverseService;
import ext.tianma.bom.util.ClassificationUtil;
import ext.tianma.bom.util.EnumerationUtil;
import ext.tianma.bom.util.GenericUtil;
import ext.tianma.number.util.PartUtil;
import ext.tianma.part.finishedProduct.util.CSMUtil;
import ext.tianma.part.finishedProduct.util.TypesUtil;
import ext.tianma.part.finishedProduct.vo.ClassAttrRuleVo;
import ext.tianma.part.report.searchAPL.util.APLUtil;
import ext.tianma.util.TMUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.dom4j.DocumentException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.remoting.support.RemoteAccessor;
import org.springframework.stereotype.Service;
import wt.csm.navigation.ClassificationNode;
import wt.csm.navigation.litenavigation.ClassificationNodeDefaultView;
import wt.csm.navigation.service.ClassificationHelper;
import wt.csm.navigation.service.ClassificationObjectsFactory;
import wt.fc.PersistenceHelper;
import wt.fc.QueryResult;
import wt.fc.ReferenceFactory;
import wt.iba.definition.FloatDefinition;
import wt.iba.definition.IntegerDefinition;
import wt.iba.definition.StringDefinition;
import wt.iba.definition.TimestampDefinition;
import wt.iba.definition.litedefinition.AttributeDefDefaultView;
import wt.iba.value.*;
import wt.part.WTPart;
import wt.part.WTPartMaster;
import wt.part.WTPartUsageLink;
import wt.query.*;
import wt.session.SessionHelper;
import wt.type.ClientTypedUtility;
import wt.type.TypeDefinitionForeignKey;
import wt.type.TypeDefinitionReference;
import wt.type.Typed;
import wt.util.*;
import wt.vc.VersionControlHelper;
import wt.vc.config.LatestConfigSpec;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.rmi.RemoteException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;

/**
 * 类名: APLService </br>
 * 包名: ext.tianma.part.report.searchAPL.service
 * 描述: 报表-APL材料
 * @author xucr
 * 创建时间: 2020年6月16日
 * 发布版本: V1.0
 */
@Service
public class APLService extends RemoteAccessor{
	
	private static final String SPLITVALUE = ",";
	public static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
	public static final Map<String, String> titleMap = new LinkedHashMap<String, String>();//有顺序的map
	public static final Map<String, String> frozenColumnsMap = new LinkedHashMap<String, String>();//有顺序的map
	public static final Map<String, String> layuiMap = new LinkedHashMap<String, String>();//有顺序的map
	public static final Set<String> enumset=new HashSet<String>();
	static {
		/**
		 * EasyUI 表格的列定义
		 * */
		//固定列
		frozenColumnsMap.put("name", "名称");
		//横向列
		titleMap.put("number","编码");
		titleMap.put("createstampa2","创建时间");
		titleMap.put("version","版本");
//		titleMap.put("Supplier","原材料供应商");
		titleMap.put("aplBrand", "品牌商");
		titleMap.put("IsTemporaryMaterial","是否为临时材料");
		titleMap.put("UsableRange1","使用范围(消费品/LTPS-手机产品+中尺寸产品)");
		titleMap.put("UsableRange2","使用范围(消费品/a-si-手机产品)");
		titleMap.put("UsableRange3","使用范围(消费品/OLED-手机产品)");
		titleMap.put("UsableRange4","使用范围(消费品/OLED-穿戴产品)");
		titleMap.put("UsableRange5","使用范围(车载品-车载产品)");
		titleMap.put("UsableRange6","使用范围(车载品-Auto2020产品)");
		titleMap.put("UsableRange7","使用范围(工业品-工业I产品)");
		titleMap.put("UsableRange8","使用范围(工业品-工业II/工业III产品)");
		titleMap.put("environmentalLevel","环保等级");
//		titleMap.put("materialState","材料状态");
		titleMap.put("MaterialType","材料型号");
		titleMap.put("releaseSite","release产地");
		titleMap.put("MtlNote","备注");

		/**
		 * LayUI 表格的列定义
		 * */
		layuiMap.put("operation", "操作");
		layuiMap.put("name", "名称");
		layuiMap.put("number","编码");
		layuiMap.put("aplBrand", "品牌商");
		layuiMap.put("MaterialType","材料型号");
		layuiMap.put("modifytime","修改时间");
		layuiMap.put("IsTemporaryMaterial","是否为临时材料");
		layuiMap.put("UsableRange1","使用范围(消费品/LTPS-手机产品+中尺寸产品)");
		layuiMap.put("UsableRange2","使用范围(消费品/a-si-手机产品)");
		layuiMap.put("UsableRange3","使用范围(消费品/OLED-手机产品)");
		layuiMap.put("UsableRange4","使用范围(消费品/OLED-穿戴产品)");
		layuiMap.put("UsableRange5","使用范围(车载品-车载产品)");
		layuiMap.put("UsableRange6","使用范围(车载品-Auto2020产品)");
		layuiMap.put("UsableRange7","使用范围(工业品-工业I产品)");
		layuiMap.put("UsableRange8","使用范围(工业品-工业II/工业III产品)");
		layuiMap.put("MtlNote","备注");
		layuiMap.put("environmentalLevel","环保等级");
		layuiMap.put("releaseSite","release产地");
		layuiMap.put("createstampa2","创建时间");
		layuiMap.put("version","版本");
//		layuiMap.put("Supplier","原材料供应商");
//		layuiMap.put("materialState","材料状态");



		enumset.add("UsableRange1");
		enumset.add("UsableRange2");
		enumset.add("UsableRange3");
		enumset.add("UsableRange4");
		enumset.add("UsableRange5");
		enumset.add("UsableRange6");
		enumset.add("UsableRange7");
		enumset.add("UsableRange8");

	}
	
	/**
	 * 查询报表
	 * @param params
	 * @author xucr
	 * @throws Exception 
	 * @throws WTException 
	 * @CreateDate 2020年6月16日
	 */
	@SuppressWarnings("unchecked")
	public String queryAPL(String params) throws Exception {
		JSONObject rsult = new JSONObject();
		try {
			List<WTPart> parts = queryAPLPart(params);
			
			List<Object> datalist = new ArrayList<Object>();//基础数据
			
			JSONObject allData = new JSONObject();
			Map<String, String> obj = null;
			
			//构造动态表格 title、列宽(用easyui时，最前面的序号不能要)
//			String title = "名称<i title='升序' class='iconfont down'>&#xe604;</i>,编码<i title='升序' class='iconfont down'>&#xe604;</i>,创建时间,版本,"
			String title = "序号,名称<i title='升序' class='iconfont down'>&#xe604;</i>,编码<i title='升序' class='iconfont down'>&#xe604;</i>,创建时间,版本,"
					+ "品牌商,是否为临时材料,使用范围(消费品/LTPS-手机产品+中尺寸产品),使用范围(消费品/a-si-手机产品),使用范围(消费品/OLED-手机产品),使用范围(消费品/OLED-穿戴产品),使用范围(车载品-车载产品),使用范围(车载品-Auto2020产品),使用范围(工业品-工业I产品),使用范围(工业品-工业II/工业III产品),环保等级,材料型号,release产地,";

			String titleKey = "name,number,createstampa2,version,aplBrand,IsTemporaryMaterial,UsableRange1,UsableRange2,UsableRange3,UsableRange4,UsableRange5,UsableRange6,UsableRange7,UsableRange8,environmentalLevel,MaterialType,releaseSite,";

			String widths1 = "5%,10%,10%,10%,10%,10%,10%,10%,10%,10%,10%,10%,10%,10%,10%,10%,10%,10%,";

			/**
			 * 原材料供应商        	Supplier
			 * 是否为临时材料  	IsTemporaryMaterial     枚举值列表 使用的全局枚举: 是否
			 * 使用范围			UsableRange				合法值列表
			 * 环保等级			environmentalLevel		合法值列表
			 * 材料状态			materialState			合法值列表
			 * 材料型号			MaterialType
			 * release产地		releaseSite				合法值列表
			 * */
			
			String attrValues = "";//分类属性显示名称
			String attrKeys = "";// 分类属性内部名称
			
			JSONArray array = new JSONArray(params);
			JSONObject params_obj = array.getJSONObject(0);
			List<String> permission = null;
			
			//所有的搜索控件，均是以其内部名称命名id
			//下拉框查询条件
		    JSONObject selectParams = params_obj.getJSONObject("params2");
			if(selectParams.has("select1") && StringUtils.isNotBlank(selectParams.getString("select1"))) {
				Long nodeId =  Long.valueOf(selectParams.getString("select1"));
				permission = APLConfig.getKeyToListByNode("wt.csm.navigation.ClassificationNode:" + nodeId);
				Map<String, Object> map = getGridParams(nodeId, permission);
				attrKeys += (String) map.get("attrKeys");
				titleKey += (String) map.get("titleKey");
				attrValues += (String) map.get("attrValues");
				widths1 += (String) map.get("widths1");
			}
			
			if(null != parts && parts.size() > 0) {
				String[] attrKeyArry = attrKeys.split(SPLITVALUE);
				String[] attrValueArry = attrValues.split(SPLITVALUE);
				Locale loc = SessionHelper.getLocale();
				Set<String> ibaKeys=new HashSet<String>();
				if(null != permission && permission.size() > 0){
					ibaKeys.addAll(permission);
				}
				ibaKeys.add("MaterialType");
				ibaKeys.add("aplBrand");
				ibaKeys.add("IsTemporaryMaterial");
				ibaKeys.add("UsableRange1");
				ibaKeys.add("UsableRange2");
				ibaKeys.add("UsableRange3");
				ibaKeys.add("UsableRange4");
				ibaKeys.add("UsableRange5");
				ibaKeys.add("UsableRange6");
				ibaKeys.add("UsableRange7");
				ibaKeys.add("UsableRange8");
				ibaKeys.add("EnvProtLevel");
				ibaKeys.add("releaseSite");
//				ibaKeys.add("MtlNote");
				Map<String, String> maps = EnumerationUtil.getEnumerationValues("Level"); // 得到等级枚举
				for(WTPart part : parts) {
					obj = new LinkedHashMap<String, String>();//有顺序的map
					String version = CommonPDMUtil.getVersion(part);
					LWCNormalizedObject lwcObject = new LWCNormalizedObject(part, null, loc, null);
					lwcObject.load(ibaKeys);
//					String name = MaterielService.getUrlLink(part, false);
					String name = part.getName();
					obj.put("name", name);
					obj.put("number", part.getNumber());
					obj.put("createstampa2", WTStandardDateFormat.format(part.getCreateTimestamp(), "yyyy-MM-dd"));
					obj.put("version", version);
//					obj.put("Supplier", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "Supplier")));
					obj.put("aplBrand", TMUtil.conversion(convertToString(lwcObject.getAsString("aplBrand"))));
					obj.put("IsTemporaryMaterial", TMUtil.conversion(convertToString(lwcObject.getAsString("IsTemporaryMaterial"))));
					obj.put("UsableRange1",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString("UsableRange1")))));
					obj.put("UsableRange2",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString("UsableRange2")))));
					obj.put("UsableRange3",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString("UsableRange3")))));
					obj.put("UsableRange4",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString("UsableRange4")))));
					obj.put("UsableRange5",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString("UsableRange5")))));
					obj.put("UsableRange6",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString("UsableRange6")))));
					obj.put("UsableRange7",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString("UsableRange7")))));
					obj.put("UsableRange8",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString("UsableRange8")))));
					obj.put("environmentalLevel", TMUtil.conversion(convertToString(lwcObject.getAsString("EnvProtLevel"))));
//					obj.put("materialState", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "materialState")));
					obj.put("MaterialType", TMUtil.conversion(convertToString(lwcObject.getAsString("MaterialType"))));
					obj.put("releaseSite", TMUtil.conversion(convertToString(lwcObject.getAsString("releaseSite"))));
//					obj.put("MtlNote", TMUtil.conversion(convertToString(lwcObject.getAsString("MtlNote"))));
					
					//开始封装分类属性
					if(!"".equals(attrKeys)) {
						for(int j = 0 ; j < attrKeyArry.length; j++) {
							List<String> as = Arrays.asList(title.split(SPLITVALUE));
							//控制没有权限的不展示
							if(null != permission && !permission.contains(attrKeyArry[j])) {
								continue;
							}
							if(as.contains(attrValueArry[j])) {//如果表格title包含了该列
								if(obj.containsKey(attrKeyArry[j])) {
									String hv = obj.get(attrKeyArry[j]);
									obj.put(attrKeyArry[j], hv + "," + TMUtil.conversion(convertToString(lwcObject.getAsString(attrKeyArry[j]))));
								} else {
									obj.put(attrKeyArry[j], TMUtil.conversion(convertToString(lwcObject.getAsString(attrKeyArry[j]))));
								}
							} else {
								title += attrValueArry[j] + SPLITVALUE;
								obj.put(attrKeyArry[j], TMUtil.conversion(convertToString(lwcObject.getAsString(attrKeyArry[j]))));
							}
						}
					}
					datalist.add(obj);
				}
				
				allData.put("datalist", datalist);
				allData.put("title", title.split(SPLITVALUE));
				allData.put("widths1", widths1.split(SPLITVALUE));
				allData.put("key", titleKey.split(SPLITVALUE));
				
				rsult.put("data", allData);
				rsult.put("status", "success");
				rsult.put("message", "查询成功!");
			} else {
				allData.put("datalist", datalist);
				rsult.put("data", allData);
				rsult.put("status", "success");
				rsult.put("message", "未查到！");
			}
		} catch (JSONException | WTException e) {
			rsult.put("status", "error");
			rsult.put("message", "接口错误！");
			e.printStackTrace();
		}
		return rsult.toString();
	}
	
	@SuppressWarnings("unchecked")
	//不用方法
	public String queryAPLEasyUI(String params) throws Exception {
		JSONObject rsult = new JSONObject();
		try {
			List<WTPart> parts = queryAPLPart(params);
			
			List<Object> datalist = new ArrayList<Object>();//基础数据
			
			Map<String, String> obj = null;
			/**
			 * 原材料供应商        	Supplier
			 * 是否为临时材料  	IsTemporaryMaterial     枚举值列表 使用的全局枚举: 是否
			 * 使用范围			UsableRange				合法值列表
			 * 环保等级			environmentalLevel		合法值列表
			 * 材料状态			materialState			合法值列表
			 * 材料型号			MaterialType
			 * release产地		releaseSite				合法值列表
			 * */
			
			JSONArray array = new JSONArray(params);
			JSONObject params_obj = array.getJSONObject(0);
			List<String> permission = null;
			
			//所有的搜索控件，均是以其内部名称命名id
			 //下拉框查询条件
		    JSONObject selectParams = params_obj.getJSONObject("params2");
		    JSONArray columns = null;
		    JSONArray frozenColumns = null;
		    Long nodeId =  null;
			if(selectParams.has("select1") && StringUtils.isNotBlank(selectParams.getString("select1"))) {
				nodeId = Long.valueOf(selectParams.getString("select1"));
				permission = APLConfig.getKeyToListByNode("wt.csm.navigation.ClassificationNode:" + nodeId);
			}
			
			Map<String, Object> map = getGridParamsEasyUI(nodeId, permission);
			columns = (JSONArray) map.get("columns");
			frozenColumns = (JSONArray) map.get("frozenColumns");
			
			String usableRangeKey = "";
			if (selectParams.has("UsableRange") && StringUtils.isNotEmpty(selectParams.getString("UsableRange"))) {
				usableRangeKey = selectParams.getString("UsableRange");
			}
			
			if(null != parts && parts.size() > 0) {
				for(WTPart part : parts) {
					obj = new LinkedHashMap<String, String>();//有顺序的map
					String version = CommonPDMUtil.getVersion(part);
					String name = MaterielService.getUrlLink(part, false);
					obj.put("name", name);
					obj.put("number", part.getNumber());
					obj.put("createstampa2", WTStandardDateFormat.format(part.getCreateTimestamp(), "yyyy-MM-dd"));
					obj.put("version", version);
//					obj.put("Supplier", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "Supplier")));
					obj.put("aplBrand", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "aplBrand")));
					obj.put("IsTemporaryMaterial", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "IsTemporaryMaterial")));
//					obj.put("UsableRange", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "UsableRange")));
					obj.put("UsableRange", getRangeToLevel(part, usableRangeKey));
					obj.put("environmentalLevel", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "EnvProtLevel")));
//					obj.put("materialState", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "materialState")));
					obj.put("MaterialType", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "MaterialType")));
					obj.put("releaseSite", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "releaseSite")));
					
					//开始封装分类属性
					if(null != permission && permission.size() > 0) {
						HashMap<String, Object> ccs = getNodeIBAByPart2(part);
						for(String key : permission) {
							List<String> s = (List<String>) ccs.get(key);
							if(null != s && s.size() > 0) {
								obj.put(key, TMUtil.conversion((String) s.get(0)));
							}
						}
					}
					datalist.add(obj);
				}
				
				rsult.put("total", datalist.size());
				rsult.put("rows", datalist);
				rsult.put("columns", columns);
				rsult.put("frozenColumns", frozenColumns);
				rsult.put("status", "success");
				rsult.put("message", "查询成功!");
			} else {
				//当没有数据时，构造空的数据，否则前端datagrid中不会执行onsuccessload，导致表格不会刷新，保留上一次查询到的数据
				datalist.add(new Object());
				rsult.put("total", 0);
				rsult.put("rows", datalist);
				rsult.put("columnsLength", columns.length());
				
				rsult.put("columns", columns);
				rsult.put("frozenColumns", frozenColumns);
				rsult.put("status", "success");
				rsult.put("message", "未查到！");
			}
		} catch (JSONException | WTException e) {
			rsult.put("status", "error");
			rsult.put("message", "接口错误！");
			e.printStackTrace();
		}
		return rsult.toString();
	}
	
	@SuppressWarnings("unchecked")
	public String queryAPLLayUI(String params) throws Exception {
		JSONObject rsult = new JSONObject();
		try {
			List<WTPart> parts = queryAPLPart(params);
			
			List<Object> datalist = new ArrayList<Object>();//基础数据
			
			Map<String, String> obj = null;
			/**
			 * 原材料供应商        	Supplier
			 * 是否为临时材料  	IsTemporaryMaterial     枚举值列表 使用的全局枚举: 是否
			 * 使用范围			UsableRange				合法值列表
			 * 环保等级			environmentalLevel		合法值列表
			 * 材料状态			materialState			合法值列表
			 * 材料型号			MaterialType
			 * release产地		releaseSite				合法值列表
			 * */
			
			JSONArray array = new JSONArray(params);
			JSONObject params_obj = array.getJSONObject(0);
			List<String> permission = null;
			
			//所有的搜索控件，均是以其内部名称命名id
			 //下拉框查询条件
		    JSONObject selectParams = params_obj.getJSONObject("params2");
		    JSONArray columns = null;
		    Long nodeId =  null;
			if(selectParams.has("select1") && StringUtils.isNotBlank(selectParams.getString("select1"))) {
				nodeId = Long.valueOf(selectParams.getString("select1"));
				permission = APLConfig.getKeyToListByNode("wt.csm.navigation.ClassificationNode:" + nodeId);
			}
			
			Map<String, Object> map = getGridParamsLayUI(nodeId, permission);
			columns = (JSONArray) map.get("columns");
			if(null != parts && parts.size() > 0) {
				Locale loc = SessionHelper.getLocale();
				Set<String> ibaKeys=new HashSet<String>();
				if(null != permission && permission.size() > 0){
					ibaKeys.addAll(permission);
				}
				ibaKeys.add("MaterialType");
				ibaKeys.add("aplBrand");
				ibaKeys.add("IsTemporaryMaterial");
				ibaKeys.add("UsableRange1");
				ibaKeys.add("UsableRange2");
				ibaKeys.add("UsableRange3");
				ibaKeys.add("UsableRange4");
				ibaKeys.add("UsableRange5");
				ibaKeys.add("UsableRange6");
				ibaKeys.add("UsableRange7");
				ibaKeys.add("UsableRange8");
				ibaKeys.add("EnvProtLevel");
				ibaKeys.add("releaseSite");
				ibaKeys.add("MtlNote");
				Map<String, String> maps = EnumerationUtil.getEnumerationValues("Level"); // 得到等级枚举
				for(WTPart part : parts) {
					String num = part.getNumber();
					obj = new LinkedHashMap<String, String>();//有顺序的map
					LWCNormalizedObject lwcObject = new LWCNormalizedObject(part, null, loc, null);
					lwcObject.load(ibaKeys);
					String version = CommonPDMUtil.getVersion(part);
					String name = MaterielService.getUrlLink(part, false);
					String materialType = TMUtil.conversion(convertToString(lwcObject.getAsString( "MaterialType")));
					String href = "/Windchill/netmarkets/jsp/ext/BOMECO/tianma/materialPages/APL/ReverseAPL.html?materialType=" + materialType;
					obj.put("operation", "<a href='"+href+"' target='_blank'> 反查 </a>");
					obj.put("name", name);
					obj.put("number", part.getNumber());
					obj.put("createstampa2", WTStandardDateFormat.format(part.getCreateTimestamp(), "yyyy-MM-dd"));
					obj.put("modifytime", WTStandardDateFormat.format(part.getModifyTimestamp(), "yyyy-MM-dd"));
					obj.put("version", version);
//					obj.put("Supplier", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "Supplier")));
					obj.put("aplBrand", TMUtil.conversion(convertToString(lwcObject.getAsString("aplBrand"))));
					obj.put("IsTemporaryMaterial", TMUtil.conversion(convertToString(lwcObject.getAsString( "IsTemporaryMaterial"))));
//					obj.put("UsableRange", TMUtil.conversion(usableRangeEnumValue));
					obj.put("UsableRange1",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString( "UsableRange1")))));
					obj.put("UsableRange2",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString( "UsableRange2")))));
					obj.put("UsableRange3",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString( "UsableRange3")))));
					obj.put("UsableRange4",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString( "UsableRange4")))));
					obj.put("UsableRange5",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString( "UsableRange5")))));
					obj.put("UsableRange6",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString( "UsableRange6")))));
					obj.put("UsableRange7",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString( "UsableRange7")))));
					obj.put("UsableRange8",TMUtil.conversion(convertEnumToValue(maps,convertToString(lwcObject.getAsString( "UsableRange8")))));
					obj.put("environmentalLevel", TMUtil.conversion(convertToString(lwcObject.getAsString( "EnvProtLevel"))));
//					obj.put("materialState", TMUtil.conversion((String) IBAUtil.getIBAValue(part, "materialState")));
					obj.put("MaterialType", materialType);
					obj.put("releaseSite", TMUtil.conversion(convertToString(lwcObject.getAsString( "releaseSite"))));
					obj.put("MtlNote", TMUtil.conversion(convertToString(lwcObject.getAsString( "MtlNote"))));
					//开始封装分类属性
					if(null != permission && permission.size() > 0) {

						//性能优化,可以已经存在,直接取值
//						HashMap<String, Object> ccs = getNodeIBAByPart2(part);
//						for(String key : permission) {
//							List<String> s = (List<String>) ccs.get(key);
//							if(null != s && s.size() > 0) {
//								obj.put(key, TMUtil.conversion((String) s.get(0)));
//							}
//						}
						for(String key : permission) {
//							Vector ibavalues = IBAUtil.getIBAValue2(part, key);
//							String value = "";
//							if(null != ibavalues && ibavalues.size() > 0) {
//								for(int i = 0 ; i < ibavalues.size(); i++) {
//									value += ibavalues.get(i) + SPLITVALUE;
//								}
//								TMUtil.clearEndStr(value,SPLITVALUE);
//							}
							//permission中存在存在枚举,此处再次赋值会被覆盖.枚举值在之前处理掉了
							if(enumset.contains(key)){
								continue;
							}
							obj.put(key, TMUtil.conversion(convertToString(lwcObject.getAsString(key))));
						}
					}
					datalist.add(obj);
				}
				rsult.put("count", datalist.size());
				rsult.put("data", datalist);
				rsult.put("columns", columns);
				rsult.put("code", "0");
				rsult.put("msg", "");
			} else {
				//当没有数据时，构造空的数据，否则前端datagrid中不会执行onsuccessload，导致表格不会刷新，保留上一次查询到的数据
				rsult.put("count", 0);
				rsult.put("data", "[]");//layui api提到，当没有数据时，要返回[]
				rsult.put("columnsLength", columns.length());
				
				rsult.put("columns", columns);
				rsult.put("code", "1");
				rsult.put("msg", "您查询的数据不存在!");
			}
		} catch (Exception e) {
			rsult.put("count", 0);
			rsult.put("data", "[]");
			rsult.put("code", "1");
			rsult.put("msg", "接口异常!");
			e.printStackTrace();
		}
		return rsult.toString();
	}
	public String convertEnumToValue(Map<String,String> maps,String keyValue){
		String result=keyValue;
		if(maps.containsKey(keyValue)){
			result=maps.get(keyValue);
		}
		return result;
	}
	public String convertToString(Object object){
		StringBuilder sb = new StringBuilder();
		if(object!=null) {
			Object[] var3 = object instanceof Object[] ? (Object[]) ((Object[]) object) : new Object[]{object};
			for (Object temp : var3) {
				String var9 = (String) temp;
				sb.append(var9 + ",");
			}
			if (sb.length() > 0) {
				sb.deleteCharAt(sb.length() - 1);
			}
		}
		return sb.toString();
	}
	/**
	 * 获取范围对应的等级值
	 * 
	 * @param part
	 * @param usableRangeKey
	 * @return
	 * @throws RemoteException
	 * @throws WTException
	 */
	public String getRangeToLevel(WTPart part, String usableRangeKey) throws RemoteException, WTException {
		String usableRangeEnumKey = "";
		String usableRangeEnumValue = "";

		Map<String, String> maps = EnumerationUtil.getEnumerationValues("Level"); // 得到等级枚举
		if (StringUtils.isNotEmpty(usableRangeKey)) {
			usableRangeEnumKey = (String) IBAUtil.getIBAValue(part, usableRangeKey);
			if (StringUtils.isNotEmpty(usableRangeEnumKey)) { // 有可能该范围在物料上没有值
				usableRangeEnumValue = maps.containsKey(usableRangeEnumKey) ? maps.get(usableRangeEnumKey) : "";
			}
		}
		return usableRangeEnumValue;
	}
	
	/**
	 * 按条件搜索部件
	 * @param params
	 * @return
	 * @author xucr
	 * @throws Exception 
	 * @CreateDate 2020年6月17日
	 */
	public List<WTPart> queryAPLPart(String params) throws Exception {
		List<WTPart> parts = new ArrayList<WTPart>();
		
		QuerySpec qs = new QuerySpec();
	    int p = qs.appendClassList(WTPart.class, true);
	    qs.setAdvancedQueryEnabled(true);
	    
	    //仅查询APL材料
		TypeDefinitionReference clientType = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.AVLMaterial");
		SearchCondition sc = new SearchCondition(WTPart.class,
				Typed.TYPE_DEFINITION_REFERENCE + "." + TypeDefinitionReference.KEY + "." + TypeDefinitionForeignKey.BRANCH_ID, 
				SearchCondition.EQUAL, clientType.getKey().getBranchId());
		qs.appendWhere(sc, new int[] { 0 });
		
		//最新小版本
		qs.appendAnd();
		SearchCondition sc1 = new SearchCondition(WTPart.class,"iterationInfo.latest", SearchCondition.IS_TRUE, true);
		qs.appendWhere(sc1, new int[] { 0 });
		
		//最新大版本
		addSearchConditionLasterVersion(qs, WTPart.class,null);
		
		if(StringUtils.isNotBlank(params)) {
			JSONArray array = new JSONArray(params);
		    JSONObject paramsAll = array.getJSONObject(0);
		    
		    //基础查询条件
		    JSONObject obj = paramsAll.getJSONObject("params1");
		    
		    //下拉框查询条件
		    JSONObject selectParams = paramsAll.getJSONObject("params2");
		    
		    //分类查询条件
		    JSONObject classObj = paramsAll.getJSONObject("params3");
		    
		    //编码
		    String number = obj.getString("number");
			if(obj.has("number") && StringUtils.isNotBlank(number)) {
				SearchCondition scDocNumber = new SearchCondition(WTPart.class,WTPart.NUMBER,SearchCondition.LIKE,"%"+number+"%");
				qs.appendAnd();
            	qs.appendWhere(scDocNumber,new int[]{ p });
			}
			
			//名称
			String name = obj.getString("name");
			if(obj.has("name") && StringUtils.isNotBlank(name)) {
				SearchCondition scDocName = new SearchCondition(WTPart.class,WTPart.NAME,SearchCondition.LIKE,"%"+name+"%",false);
				qs.appendAnd();
            	qs.appendWhere(scDocName,new int[]{ p });
			}
			
			//创建时间：Form
			String dt = obj.getString("dt");
			if(obj.has("dt") && StringUtils.isNotBlank(dt)) {
				Date startDate = dateFormat.parse(dt);
				SearchCondition scDocTime = new SearchCondition(WTPart.class,WTPart.CREATE_TIMESTAMP,
						SearchCondition.GREATER_THAN_OR_EQUAL, new Timestamp(startDate.getTime()));
				qs.appendAnd();
            	qs.appendWhere(scDocTime,new int[]{ p });
			}
			
			//创建时间：To
			String dt1 = obj.getString("dt1");
			if(obj.has("dt1") && StringUtils.isNotBlank(dt1)) {
				Date endDate = dateFormat.parse(dt1);
				SearchCondition scDocTime = new SearchCondition(WTPart.class,WTPart.CREATE_TIMESTAMP,
						SearchCondition.LESS_THAN_OR_EQUAL, new Timestamp(endDate.getTime()));
				qs.appendAnd();
            	qs.appendWhere(scDocTime,new int[]{ p });
			}
			/**
			 * 原材料供应商        	Supplier
			 * 是否为临时材料  	IsTemporaryMaterial     枚举值列表 使用的全局枚举: 是否
			 * 使用范围			UsableRange				合法值列表
			 * 环保等级			environmentalLevel		合法值列表
			 * 材料状态			materialState			合法值列表
			 * 材料型号			MaterialType
			 * release产地		releaseSite				合法值列表
			 * */
			
			Hashtable<String, Object> strMap = new Hashtable<String, Object>();//字符串查询
			Hashtable<String, String> specialMap = new Hashtable<String, String>();//特殊查询
			Hashtable<String, Object> floatMap = new Hashtable<String, Object>();//float查询
			Hashtable<String, Object> intMap = new Hashtable<String, Object>();//int查询
			Hashtable<String, Object> timeMap = new Hashtable<String, Object>();//time查询
			Hashtable<String, Object> notNullMap = new Hashtable<String, Object>();//不为空的查询
			//原材料供应商
			if(obj.has("aplBrand") && StringUtils.isNotBlank(obj.getString("aplBrand"))) {
				strMap.put("aplBrand", obj.getString("aplBrand"));
			}
			//是否为临时材料
			if(selectParams.has("IsTemporaryMaterial") && StringUtils.isNotBlank(selectParams.getString("IsTemporaryMaterial"))) {
				strMap.put("IsTemporaryMaterial", selectParams.getString("IsTemporaryMaterial"));
			}
			//使用范围
//			if(selectParams.has("UsableRange") && StringUtils.isNotBlank(selectParams.getString("UsableRange"))) {
////				strMap.put("UsableRange", selectParams.getString("UsableRange"));
//				notNullMap.put(selectParams.getString("UsableRange"), selectParams.getString("UsableRange"));
//			}
			//使用范围
			if(selectParams.has("UsableRange1") && StringUtils.isNotBlank(selectParams.getString("UsableRange1"))) {
				String tempString=convertArrayToString(selectParams.getString("UsableRange1"));
				specialMap.put("UsableRange1", tempString);
			}
			if(selectParams.has("UsableRange2") && StringUtils.isNotBlank(selectParams.getString("UsableRange2"))) {

				specialMap.put("UsableRange2", convertArrayToString(selectParams.getString("UsableRange2")));
			}
			if(selectParams.has("UsableRange3") && StringUtils.isNotBlank(selectParams.getString("UsableRange3"))) {
				specialMap.put("UsableRange3", convertArrayToString(selectParams.getString("UsableRange3")));
			}
			if(selectParams.has("UsableRange4") && StringUtils.isNotBlank(selectParams.getString("UsableRange4"))) {
				specialMap.put("UsableRange4", convertArrayToString(selectParams.getString("UsableRange4")));
			}
			if(selectParams.has("UsableRange5") && StringUtils.isNotBlank(selectParams.getString("UsableRange5"))) {
				specialMap.put("UsableRange5", convertArrayToString(selectParams.getString("UsableRange5")));
			}
			if(selectParams.has("UsableRange6") && StringUtils.isNotBlank(selectParams.getString("UsableRange6"))) {
				specialMap.put("UsableRange6", convertArrayToString(selectParams.getString("UsableRange6")));
			}
			if(selectParams.has("UsableRange7") && StringUtils.isNotBlank(selectParams.getString("UsableRange7"))) {
				specialMap.put("UsableRange7", convertArrayToString(selectParams.getString("UsableRange7")));
			}
			if(selectParams.has("UsableRange8") && StringUtils.isNotBlank(selectParams.getString("UsableRange8"))) {
				specialMap.put("UsableRange8", convertArrayToString(selectParams.getString("UsableRange8")));
			}


			//环保等级
			if(selectParams.has("environmentalLevel") && StringUtils.isNotBlank(selectParams.getString("environmentalLevel"))) {
				strMap.put("EnvProtLevel", selectParams.getString("environmentalLevel"));
			}
//			//材料状态
//			if(selectParams.has("materialState") && StringUtils.isNotBlank(selectParams.getString("materialState"))) {
//				strMap.put("materialState", selectParams.getString("materialState"));
//			}
			//材料型号
			if(obj.has("MaterialType") && StringUtils.isNotBlank(obj.getString("MaterialType"))) {
				strMap.put("MaterialType", obj.getString("MaterialType"));
			}
			//release产地
			if(selectParams.has("releaseSite") && StringUtils.isNotBlank(selectParams.getString("releaseSite"))) {
				strMap.put("releaseSite", selectParams.getString("releaseSite"));
			}
			//过滤部件分类：当选择分类后，仅只查询所选分类的部件
			if(selectParams.has("select1") && StringUtils.isNotBlank(selectParams.getString("select1"))){
				  //select * from pdm.referencevalue r where r.ida3b5=所选分类id and r.ida3a4 = partida2a2; 
				Long nodeId =  Long.valueOf(selectParams.getString("select1"));
				int r = qs.appendClassList(ReferenceValue.class, false);
				SearchCondition s1 = new SearchCondition(ReferenceValue.class,"theIBAReferenceableReference.key.id",
						SearchCondition.EQUAL, nodeId);
				SearchCondition s2 = new SearchCondition(ReferenceValue.class,"theIBAHolderReference.key.id",
						WTPart.class, "thePersistInfo.theObjectIdentifier.id");
				
				qs.appendAnd();
				qs.appendWhere(s1,new int[]{ r });
				
				qs.appendAnd();
				qs.appendWhere(s2,new int[]{ r, 0 });
			}
			
			//构造分类属性的查询条件
			if(null != classObj && classObj.length() > 0) {
				Iterator iter =  classObj.keys();
				
				String nodeOid = "wt.csm.navigation.ClassificationNode:" + selectParams.getString("select1");
				ReferenceFactory rf = new ReferenceFactory();
				ClassificationNode node = (ClassificationNode) rf.getReference(nodeOid).getObject();
				ClassAttrRuleVo vo = null;
				
//				Map<String,String> m = CSMUtil.getClassNodeAllIBAs(node);
				
				while (iter.hasNext()) {
					String key = (String) iter.next();
					String value = classObj.getString(key);
					vo = CSMUtil.getClassAttrInfo(node, key);//此方法在这里使用，还需要优化
					
//					String datatype = m.get(key);
					
					if(StringUtils.isNotBlank(value)) {
						 //先判断属性类型，然后构造查询条件：String、float等类型
						if("wt.iba.definition.StringDefinition".equals(vo.getDataType())) {//字符串
							strMap.put(key, value);
						} else if("wt.iba.definition.FloatDefinition".equals(vo.getDataType())) {
							floatMap.put(key, value);
						} else if("wt.iba.definition.IntegerDefinition".equals(vo.getDataType())) {
							intMap.put(key, value);
						} else if("wt.iba.definition.TimestampDefinition".equals(vo.getDataType())) {
							timeMap.put(key, value);
						} else if("wt.iba.definition.UnitDefinition".equals(vo.getDataType())) {
							
						} else if("wt.iba.definition.BooleanDefinition".equals(vo.getDataType())) {
							
						}
					}
				 }
			}
			//构造各类型IBA查询条件
			if(strMap.size() > 0) {
				//APLUtil.addIBAStringCondition(WTPart.class, qs, strMap, SearchCondition.LIKE, "", true);
				APLUtil.addIBAStringCondition(WTPart.class, qs, 
						strMap, SearchCondition.LIKE, "", true, StringDefinition.class, StringValue.class);
			}
			if(floatMap.size() > 0) {
				APLUtil.addIBAStringCondition(WTPart.class, qs, 
						floatMap, SearchCondition.LIKE, "", true, FloatDefinition.class, FloatValue.class);
			}
			if(intMap.size() > 0) {
				APLUtil.addIBAStringCondition(WTPart.class, qs, 
						intMap, SearchCondition.LIKE, "", true, IntegerDefinition.class, IntegerValue.class);
			}
			if(timeMap.size() > 0) {
				//AND A2.value LIKE to_date('2020-6-28','yyyy-mm-dd')
				APLUtil.addIBAStringCondition(WTPart.class, qs, 
						timeMap, SearchCondition.LIKE, "", true, TimestampDefinition.class,  TimestampValue.class);
			}
			if(notNullMap.size() > 0) {
				APLUtil.addIBAStringCondition(WTPart.class, qs, 
						notNullMap, SearchCondition.NOT_NULL, "", true, StringDefinition.class,  StringValue.class);
			}
			//特殊处理数据
			if(specialMap.size()>0){
				addIBAStringCondition(WTPart.class, qs,
						specialMap, SearchCondition.IN, "", true, StringDefinition.class, StringValue.class);
			}
		}
		
		qs.appendOrderBy(new OrderBy(new ClassAttribute(WTPart.class, "thePersistInfo.modifyStamp"), true), new int[]{p});
		logger.info("sql>>>:" + qs.toString());
	    QueryResult qr = PersistenceHelper.manager.find(qs);
		
	    while(qr.hasMoreElements()){
	    	Object o[] = (Object[])qr.nextElement();
  	      	if(o[0] instanceof WTPart){
				WTPart part = (WTPart) o[0];
				parts.add(part);
			}
  	    }
	    
		return parts;
	}

	public static String convertArrayToString(String arrayInfo) throws Exception{
		String result="";
		if(StringUtils.isNotBlank(arrayInfo)&&!"null".equalsIgnoreCase(arrayInfo)){
			JSONArray array=new JSONArray(arrayInfo);
			Set<String> set=new HashSet<>();;
			for(int i=0;i<array.length();i++){
				String temp=array.getString(i);
				set.add(temp);
			}
			result=StringUtils.join(set,",");
		}
		return result;
	}


	/**
	 * 特殊处理数据,使用枚举显示值和key进行or搜索
	 */
	public static void addIBAStringCondition(Class ibaHolderClass, QuerySpec qs,
											 Hashtable<String, String> maramsMap, String condition, String splitsign, boolean isAdd,
											 Class definitionClass, Class valueClass) throws Exception {
		Map<String, String> maps = EnumerationUtil.getEnumerationValues("Level"); // 得到等级枚举
		Enumeration<String> eIba = maramsMap.keys();
		while(eIba.hasMoreElements()) {
			String iba_name = eIba.nextElement();
			String iba_value = maramsMap.get(iba_name);
			if(StringUtils.isBlank(iba_value)){
				continue;
			}
			//PS : 如下变量不能提成公共变量，每个属性，必须要用使用自己的变量
			int sd = qs.appendClassList(definitionClass, false);
			int sv = qs.appendClassList(valueClass, false);
			ClassAttribute caValue = new ClassAttribute(valueClass,StringValue.VALUE);

			SearchCondition scName = new SearchCondition(definitionClass,"name",SearchCondition.EQUAL,iba_name);
			SearchCondition scDef = new SearchCondition(valueClass,"definitionReference.key.id", definitionClass ,WTAttributeNameIfc.ID_NAME);
			SearchCondition scDoc = new SearchCondition(valueClass,"theIBAHolderReference.key.id",ibaHolderClass,WTAttributeNameIfc.ID_NAME);

			if(qs.getConditionCount() > 0) {
				qs.appendAnd();
			}
			int p = qs.getFromClause().getPosition(ibaHolderClass);



			qs.appendWhere(scDoc,new int [] {sv, p});
			qs.appendAnd();

			qs.appendWhere(scDef,new int [] {sv, sd});
			qs.appendAnd();

			qs.appendWhere(scName,new int [] {sd});

			qs.appendAnd();
			qs.appendOpenParen();
			if(StringUtils.isNotBlank(iba_value)){
				String [] temp=iba_value.split(",");
				qs.appendWhere(new SearchCondition(caValue, SearchCondition.IN, new ArrayExpression(temp)),new int [] {sv});
				String []temp2=new String[temp.length];
				for(int i=0;i<temp.length;i++){
					temp2[i]=maps.get(temp[i]);
				}
				qs.appendOr();
				qs.appendWhere(new SearchCondition(caValue, SearchCondition.IN, new ArrayExpression(temp2)),new int [] {sv});
			}
			qs.appendCloseParen();
		}
	}

	/**
	 * 导出Excel
	 * @param params
	 * @throws Exception
	 * @author xucr
	 * @CreateDate 2020年6月24日
	 */
	public String exportExcel(String params) throws Exception {
		String result = queryAPL(params);
		JSONObject object = new JSONObject(result);
		String path = ecportExcel(object);
		return path;
	}
	
	public static String ecportExcel(JSONObject object) throws IOException, JSONException, DocumentException {
		String domain = APLConfig.getKey("windchillHome");
		String folder = "TempExcel";
		WTProperties props = WTProperties.getLocalProperties();
		String filePath = props.getProperty("wt.codebase.location") + File.separator + "temp" + File.separator + folder + File.separator;
		File targerFile = new File(filePath);
		if(!targerFile.exists()) {
			targerFile.mkdirs();
		}
		String pathAndName = filePath + "APL材料报表.xls";
		String realPath = domain + File.separator + "temp" + File.separator + folder + File.separator + "APL材料报表.xls";
		
		//1.创建HSSFWorkbook,对应一个excel
		HSSFWorkbook wb = new HSSFWorkbook();
		
		//2.在workbook中创建一个sheet，对应excel中的sheet
		HSSFSheet sheet = wb.createSheet("APL报表数据");
		
		//3.在sheet中添加表头第0行
		HSSFRow row = sheet.createRow(0);
		
		//4.创建单元格，并设置值表头 设置表头居中
	    HSSFCellStyle cellStyle = wb.createCellStyle();
	    cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);//设置居中
	    
	    // 声明列对象
	 	HSSFCell cell = null;
	 	
	 	JSONObject data = object.getJSONObject("data");
	 	JSONArray array = data.getJSONArray("datalist");
	 	if(null == array || array.length() == 0) {
	 		return "";
	 	}
	 	JSONArray title = data.getJSONArray("title");//中文标题
	 	JSONArray titleKey = data.getJSONArray("key");//英文key
	 	
	 	
 		// 创建标题
	 	
 		for (int i = 0; i < title.length(); i++) {
 			cell = row.createCell(i);
 			cell.setCellValue(title.getString(i).split("<")[0]);//列名有可能为【名称<i title='升序' class='iconfont down'>&#xe604;</i>】，处理下
 			cell.setCellStyle(cellStyle);
 		}
 		
 		//创建内容
 		for(int i =0; i<array.length(); i++) {
 			HSSFRow tempRow = sheet.createRow(i+1);
 			JSONObject jsonObject = array.getJSONObject(i);
 			
 			for(int j = 0 ; j < jsonObject.length(); j++) {
 				
 				String key = titleKey.getString(j);//按照写入的列匹配值，如果用遍历，顺序可能匹配补上
 				
 				//因为第一列是序号，没有在titleKey返回，因此0时，多写一列序号，i表示行，j表示列
 				if(j == 0) {
 					tempRow.createCell(j).setCellValue(i+1);
 				}
 				if(jsonObject.has(key)) {
 					String value = jsonObject.getString(key);
 	 				tempRow.createCell(j+1).setCellValue(value);
 				}
 			}
 			//调整每一列宽度自适应
 			sheet.autoSizeColumn((short)i);
 		}
        FileOutputStream os = new FileOutputStream(pathAndName);
        wb.write(os);
		os.flush();
		os.close();
		return realPath;
	}
	
	/**
	 * 获取分类子属性
	 * @param id 分类id，当传入0时，获取一级分类
	 * @author xucr
	 * @throws WTException 
	 * @throws JSONException 
	 * @CreateDate 2020年6月17日
	 */
	public JSONArray queryClassificationNodeById(Long id) throws WTException, JSONException {
		QuerySpec qs = new QuerySpec(ClassificationNode.class);
		qs.setAdvancedQueryEnabled(true);
		
		SearchCondition scDocName = new SearchCondition(ClassificationNode.class,"parentReference.key.id",SearchCondition.EQUAL,id);
		qs.appendWhere(scDocName,new int[]{ 0 });

		QueryResult queryResult = PersistenceHelper.manager.find(qs);
		JSONArray array = new JSONArray();
		JSONObject obj = null;
		while (queryResult.hasMoreElements()) {
			obj = new JSONObject();
			ClassificationNode c = (ClassificationNode)queryResult.nextElement();
			String nodeOid = String.valueOf(c.getPersistInfo().getObjectIdentifier().getId());
			obj.put("key", nodeOid);
			obj.put("value", c.getName());
			array.put(obj);
		}
		return array;
	}
	
	/**
	 * 递归获取子分类
	 * @param id 分类id
	 * @param nodeName 分类名称
	 * @param isNeedParent 是否需要父项
	 * @param nodes 返回结果
	 * @throws WTException
	 * @throws JSONException
	 * @author xucr
	 * @throws RemoteException 
	 * @CreateDate 2020年6月18日
	 */
	public void recursionClassificationNodeById(Long id, String nodeName, boolean isNeedParent, JSONArray nodes) throws WTException, JSONException, RemoteException {
		QuerySpec qs = new QuerySpec(ClassificationNode.class);
		qs.setAdvancedQueryEnabled(true);
		//名称或者id二选其一
		if(null != id) {
			SearchCondition scDocName = new SearchCondition(ClassificationNode.class,"parentReference.key.id",SearchCondition.EQUAL,id);
			qs.appendWhere(scDocName,new int[]{ 0 });
		} else if(StringUtils.isNotEmpty(nodeName)) {
			SearchCondition scDocName = new SearchCondition(ClassificationNode.class,ClassificationNode.NAME,SearchCondition.EQUAL,nodeName);
			qs.appendWhere(scDocName,new int[]{ 0 });
		}

		QueryResult queryResult = PersistenceHelper.manager.find(qs);
		JSONObject obj = null;
		ClassificationNode c = null;
		while (queryResult.hasMoreElements()) {
			obj = new JSONObject();
			c = (ClassificationNode)queryResult.nextElement();
			
			boolean isNotAttr = false;//分类是否存在属性
			if(isNeedParent) {
				ClassificationNodeDefaultView cndv=ClassificationObjectsFactory.newClassificationNodeDefaultView(c);
	    		cndv=ClassificationHelper.service.refreshClassificationNodeDefaultView(cndv);
	    		DefaultAttributeContainer dac = (DefaultAttributeContainer)cndv.getAttributeContainer();
				AttributeDefDefaultView avv[] = dac.getAttributeDefinitions();
				if(avv.length > 0) {
					isNotAttr = true;
				}
			} else {
				isNotAttr = true;
			}
			
			
			Long childId = c.getPersistInfo().getObjectIdentifier().getId();
			String nodeOid = String.valueOf(childId);
			obj.put("key", nodeOid);
			obj.put("value", c.getName());
			if(isNotAttr) {
				nodes.put(obj);
			}
			
			recursionClassificationNodeById(childId, "", isNeedParent, nodes);
		}
	}
	
	/**
	 * 根据父项分类，获取子分类，并封装成表格列
	 * @param nodeId
	 * @return
	 * @throws WTException
	 * @throws JSONException
	 * @author xucr
	 * @CreateDate 2020年6月18日
	 */
	private Map<String,Object> getTitle(Long nodeId) throws WTException, JSONException {
		Map<String,Object> map = new HashMap<String, Object>();
		JSONArray array = queryClassificationNodeById(nodeId);
		if(null != array && array.length() > 0) {
			JSONObject obj = null;
			String title = "";
			String columnWidth = "";
			for(int i = 0 ; i < array.length(); i++) {
				obj = array.getJSONObject(i);
				
				title += obj.getString("value") + SPLITVALUE;//标题列
				columnWidth += "10%" + SPLITVALUE;
			}
			
			map.put("title", title);
			map.put("widths1", columnWidth);
			map.put("child", array.length());//子分类长度
		}
		return map;
	}
	
	/**
	 * 根据part获取分类 返回分类属性的值（显示名称、key、value）
	 * @param part
	 * @return
	 * @author xucr
	 * @CreateDate 2020年6月18日
	 */
	public static HashMap<String, Object> getNodeIBAByPart2(WTPart part) {
		HashMap<String, Object> ibamap = new HashMap<String, Object>();
		ClassificationNode node = ClassificationUtil.getClassificationNode(part);
		try {
			Hashtable values = ext.com.iba.IBAUtil.getIBAValues(node);
			Iterator ibaiter = values.keySet().iterator();
			List<String> l = null;
			
			while (ibaiter.hasNext()) {
				String key = ibaiter.next().toString();
				String displayname = IBAUtil.getAttributeDefinition(key).getDisplayName();
				Vector ibavalues = IBAUtil.getIBAValue2(part, key);
				String value = "";
				if(null != ibavalues && ibavalues.size() > 0) {
					for(int i = 0 ; i < ibavalues.size(); i++) {
						value += ibavalues.get(i) + SPLITVALUE;
					}
					
					l = new ArrayList<String>();
					l.add(TMUtil.clearEndStr(value,SPLITVALUE));
					l.add(displayname);
					
					ibamap.put(key, l);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ibamap;
	}
	
	/**
	 * 构造表格数据
	 * @param nodeId
	 * @param permission 需要展示的
	 * @return
	 * @throws WTRuntimeException
	 * @throws WTException
	 * @author xucr
	 * @CreateDate 2020年6月23日
	 */
	public Map<String, Object> getGridParams(Long nodeId, List<String> permission) throws WTRuntimeException, WTException {
		Map<String, Object> map = new HashMap<String, Object>();
			String nodeOid = "wt.csm.navigation.ClassificationNode:" + nodeId;
			ReferenceFactory rf = new ReferenceFactory();
			ClassificationNode node = (ClassificationNode) rf.getReference(nodeOid).getObject();
			Map<String,String> attrs = CSMUtil.getClassNodeAllIBAs(node);
			
			String attrKeys = "";
			String titleKey = "";
			String attrValues = "";
			String widths1 = "";
			for(Entry<String, String> attr : attrs.entrySet()) {
				
				//控制没有权限的不展示
				if(!permission.contains(attr.getKey())) {
					continue;
				}
				
				attrKeys += attr.getKey() + SPLITVALUE;
				titleKey += attr.getKey() + SPLITVALUE;
				attrValues += attr.getValue() + SPLITVALUE;
				widths1 += "10%" + SPLITVALUE;
			}
			
			map.put("attrKeys", attrKeys);
			map.put("titleKey", titleKey);
			map.put("attrValues", attrValues);
			map.put("widths1", widths1);
			
			return map;
	}
	
	public Map<String, Object> getGridParamsEasyUI(Long nodeId, List<String> permission) throws WTRuntimeException, WTException, JSONException {
		Map<String, String> classMap = new LinkedHashMap<String, String>();//有顺序的map
		JSONArray columns = new JSONArray();
		JSONArray frozenColumns = new JSONArray();
		Map<String, Object> map = new LinkedHashMap<String, Object>();//有顺序的map
		if(null != nodeId) {
			String nodeOid = "wt.csm.navigation.ClassificationNode:" + nodeId;
			ReferenceFactory rf = new ReferenceFactory();
			ClassificationNode node = (ClassificationNode) rf.getReference(nodeOid).getObject();
			Map<String,String> attrs = CSMUtil.getClassNodeAllIBAs(node);
			
			for(Entry<String, String> attr : attrs.entrySet()) {
				if(permission.contains(attr.getKey())) {//必须在配置表中的属性才加载
					classMap.put(attr.getKey(), attr.getValue());
				}
			}
		}
		initGridColumns(titleMap, "center", "10%", columns);
		initGridColumns(classMap, "center", "10%", columns);
		initGridColumns(frozenColumnsMap, "center", "10%", frozenColumns);
		
		map.put("columns", columns);
		map.put("frozenColumns", frozenColumns);
			
		return map;
	}
	
	public Map<String, Object> getGridParamsLayUI(Long nodeId, List<String> permission) throws WTRuntimeException, WTException, JSONException {
		Map<String, String> classMap = new LinkedHashMap<String, String>();//有顺序的map
		JSONArray columns = new JSONArray();
		Map<String, Object> map = new LinkedHashMap<String, Object>();//有顺序的map
		if(null != nodeId) {
			String nodeOid = "wt.csm.navigation.ClassificationNode:" + nodeId;
			ReferenceFactory rf = new ReferenceFactory();
			ClassificationNode node = (ClassificationNode) rf.getReference(nodeOid).getObject();
			Map<String,String> attrs = CSMUtil.getClassNodeAllIBAs(node);
			
			for(Entry<String, String> attr : attrs.entrySet()) {
				if(permission.contains(attr.getKey())) {//必须在配置表中的属性才加载
					classMap.put(attr.getKey(), attr.getValue());
				}
			}
		}
		List<String> fixeds = new ArrayList<String>();
		fixeds.add("name");
		fixeds.add("number");
		fixeds.add("operation");
		fixeds.add("aplBrand");
		fixeds.add("MaterialType");
		Map<String, String> config=new HashMap<String, String>();
		config.put("operation","58");
		config.put("version","55");
		config.put("createstampa2","110");
		config.put("IsTemporaryMaterial","55");
		initGridColumns(layuiMap, config,"center", "7%", columns, fixeds);
		initGridColumns(classMap, "center", "7%", columns, null);
		
		map.put("columns", columns);
			
		return map;
	}
	
	/**
	 * 获取分类的属性
	 * @param nodeId 分类id
	 * @param not 不需要查看的
	 * @return
	 * @throws WTRuntimeException
	 * @throws WTException
	 * @author xucr
	 * @throws JSONException 
	 * @CreateDate 2020年6月23日
	 */
	public JSONArray getClassAttrsByClassId(Long nodeId, List<String> permission) throws WTRuntimeException, WTException, JSONException {
		
		String nodeOid = "wt.csm.navigation.ClassificationNode:" + nodeId;
		ReferenceFactory rf = new ReferenceFactory();
		ClassificationNode node = (ClassificationNode) rf.getReference(nodeOid).getObject();
		List<AttributeDefDefaultView> attrs = getClassNodeAllIBAs(node);
		
		logger.info("nodeOid>>" + nodeOid);
		
		JSONArray array = new JSONArray();
		JSONObject json = null;
		if(null != attrs && attrs.size() > 0) {
			for(AttributeDefDefaultView v : attrs) {
				//控制没有权限的不展示
				if(!permission.contains(v.getName())) {
					continue;
				}
				json = new JSONObject();
				json.put("key",v.getName());
				json.put("value",v.getLocalizedDisplayString());
				json.put("dataType",v.getAttributeDefinitionClassName());
				
				logger.info("key>>" + v.getName());
				logger.info("value>>" + v.getLocalizedDisplayString());
				logger.info("dataType>>" + v.getAttributeDefinitionClassName());
				array.put(json);
			}
		}		
		return array;
	}
	
    /**
     * 获取分类节点的所有属性
     * @param node
     * @return
     * @author xucr
     * @CreateDate 2020年7月6日
     */
    public static List<AttributeDefDefaultView> getClassNodeAllIBAs(ClassificationNode node) {
    	List<AttributeDefDefaultView> retMap = new ArrayList<AttributeDefDefaultView>();
    	try {
    		ClassificationNodeDefaultView cndv = ClassificationObjectsFactory.newClassificationNodeDefaultView(node);
    		cndv = ClassificationHelper.service.refreshClassificationNodeDefaultView(cndv);
    		DefaultAttributeContainer dac = (DefaultAttributeContainer)cndv.getAttributeContainer();
			AttributeDefDefaultView avv[] = dac.getAttributeDefinitions();
			retMap = Arrays.asList(avv);
        } catch (Exception e) {
    		e.printStackTrace();
    	}
    	return retMap;
    }
	
	/**
	 * 获取对象合法值列表
	 * @param typeName
	 * @param attrName
	 * @throws Exception
	 * @author xucr
	 * @CreateDate 2020年6月24日
	 */
	public JSONObject getLegalValue(String typeName, String attrName) throws Exception {
		JSONObject ob = new JSONObject();
		JSONArray array = new JSONArray();
//		List<String> list = EnumerationUtil.getTypeLegalValues(typeName, attrName);
		ArrayList<String> list = TypesUtil.getlegalValueList(typeName, attrName);
		if (list.size() > 0) {
			ob.put("status", "success");
			ob.put("message", "查询成功!");
			for (String key : list) {
				JSONObject ob1 = new JSONObject();
				ob1.put("key", key);
				ob1.put("value", key);
				array.put(ob1);
			}
			ob.put("data", array);
		} else {
			ob.put("status", "false");
			ob.put("message", "未查到！");
		}
		return ob;
	}
	
	/**
	 * 获取枚举值列表
	 * @param enumerationTypeName
	 * @return
	 * @throws JSONException
	 * @author xucr
	 * @CreateDate 2020年6月28日
	 */
	public JSONObject getEnumeration(String enumerationTypeName) throws JSONException {
		Map<String,String> maps = EnumerationUtil.getEnumerationValues(enumerationTypeName);
		JSONObject ob = new JSONObject();
		JSONArray array = new JSONArray();
		if(null != maps && maps.size() > 0) {
			ob.put("status", "success");
			ob.put("message", "查询成功!");
			
			JSONObject m = null;
			for(Entry<String, String> set: maps.entrySet() ) {
				m = new JSONObject();
				m.put("key", set.getKey());
				m.put("value", set.getValue());
				array.put(m);
			}
			ob.put("data", array);
		} else {
			ob.put("status", "false");
			ob.put("message", "未查到！");
		}
		return ob;
	}
	
	/**
	 * easyui 构造表格列
	 * @param field
	 * @param title
	 * @param align
	 * @param width
	 * @param columns
	 * @throws JSONException
	 * @author xucr
	 * @CreateDate 2020年7月3日
	 */
	public void initGridColumns(Map<String,String> titles, String align, String width, JSONArray columns) throws JSONException {
//		field:key[i],
//		title:value[i],
//		width:'10%',
//		sortable:true,
//		align: 'center'
		JSONObject obj = null;
		for(String title : titles.keySet()) {
			obj = new JSONObject();
			obj.put("field", title);
			obj.put("title", titles.get(title));
			obj.put("align", align);
			obj.put("width", width);
			obj.put("sortable", true);
			columns.put(obj);
		}
	}
	
	/**
	 * layui 构造表格列
	 * @param titles
	 * @param align
	 * @param width
	 * @param columns
	 * @param fixeds
	 * @throws JSONException
	 * @author xucr
	 * @CreateDate 2020年7月7日
	 */
	public void initGridColumns(Map<String,String> titles, String align, String width, JSONArray columns, List<String> fixeds) throws JSONException {
		JSONObject obj = null;
		for(String title : titles.keySet()) {
			obj = new JSONObject();
			if(null != fixeds && fixeds.contains(title)) {
				obj.put("fixed", "left");
			}
			obj.put("field", title);
			obj.put("title", titles.get(title));
			obj.put("align", align);
			if(StringUtils.isNotEmpty(width)) {//如果不设置宽度，则表格自动等比设置宽度
				obj.put("width", width);
			}
			obj.put("sort", true);
			columns.put(obj);
		}
	}
	/**
	 * layui 构造表格列
	 * @param titles
	 * @param align
	 * @param width
	 * @param columns
	 * @param fixeds
	 * @throws JSONException
	 * @author xucr
	 * @CreateDate 2020年7月7日
	 */
	public void initGridColumns(Map<String,String> titles,Map<String,String> configWeights, String align, String width, JSONArray columns, List<String> fixeds) throws JSONException {
		JSONObject obj = null;
		for(String title : titles.keySet()) {
			obj = new JSONObject();
			if(null != fixeds && fixeds.contains(title)) {
				obj.put("fixed", "left");
			}
			obj.put("field", title);
			obj.put("title", titles.get(title));
			obj.put("align", align);
			if(StringUtils.isNotEmpty(width)) {//如果不设置宽度，则表格自动等比设置宽度
				if(configWeights.containsKey(title)){
					obj.put("width", configWeights.get(title));
				}else {
					obj.put("width", width);
				}
			}
			obj.put("sort", true);
			columns.put(obj);
		}
	}
	
	/**
	 * 根据材料型号，反查成品、半成品
	 * @param materialNumber
	 * @return
	 * @throws Exception
	 * @author xucr
	 * @CreateDate 2020年7月29日
	 */
	public String reQueryAPL(String materialType) throws Exception {
		/**
		 * 逻辑：
		 * 1、根据【材料型号】查询原材料
		 * 2、根据原材料查询【成品、半成品】，WTPartUsageLink
		 * */
		List<String> result = null;
		if(StringUtils.isNotEmpty(materialType)) {
			Hashtable<String, Object> ibaAttrs = new Hashtable<String, Object>();
			ibaAttrs.put("MaterialType", materialType);
			result = getRawMaterial(ibaAttrs, null);
		}
//		
//		List<String> testNums = new ArrayList<String>();
//		testNums.add("0000000002");
////		String rt = getFinishedGoodByChildren(testNums);
//		String pc = getFinishedGoodByChildren2(result);
//		
//		WTPart p = PartUtil.getWTPartByNumber("0000000002");
//		TypeDefinitionReference g1 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.FinishedGood");
//		TypeDefinitionReference g2 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.SemiFinishedGood");
//		Long [] gs = {g1.getKey().getBranchId(),g2.getKey().getBranchId()};
////		List list1 = getParents(p,true);
//		Map<String,List<String>> list = new HashMap<String,List<String>>();
//		getParents(p,true, gs, list);
		
//		String r = getFinishedGoodByMaterialNumber(testNums); //按照 原材料--半成品--成品  标准结构 获取
		String r = searhMaterialPart(result); // 按照物料反查功能所写
		
//		String s1 = MaterialReverseService.searhMaterialPart(result.get(0), null);
//		String s2 = MaterialReverseService.searhMaterialPart(result.get(1), null);
		
		return r;
	}
	
	/**
	 * 根据参数查询原材料
	 * @param ibaAttrs iba属性
	 * @param attrs 对象属性
	 * @author xucr
	 * @throws Exception 
	 * @CreateDate 2020年7月28日
	 */
	public List<String> getRawMaterial(Hashtable<String, Object> ibaAttrs, Hashtable<String, Object> attrs) throws Exception {
		
		/*select wm.wtpartnumber,sv.value,sv.value2,sv.*
	    from pdm.stringvalue sv, pdm.stringdefinition sd,pdm.wtpart w,pdm.wtpartmaster wm
	   where sd.ida2a2 = sv.ida3a6
	     and sd.name = 'MaterialType'
	     and sv.value2 = 'TM_Xucr'
	     and w.ida2a2 = sv.ida3a4
	     and w.ida3masterreference = wm.ida2a2
	     and w.latestiterationinfo = 1
	     ;*/
		
		QuerySpec qs = new QuerySpec();
	    int w = qs.appendClassList(WTPart.class, true);
	    int wm = qs.appendClassList(WTPartMaster.class, false);
	    qs.setAdvancedQueryEnabled(true);
	    
	    //仅查询原材料
		TypeDefinitionReference clientType = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.RawMaterial");
		SearchCondition sc = new SearchCondition(WTPart.class,
				Typed.TYPE_DEFINITION_REFERENCE + "." + TypeDefinitionReference.KEY + "." + TypeDefinitionForeignKey.BRANCH_ID, 
				SearchCondition.EQUAL, clientType.getKey().getBranchId());
		qs.appendWhere(sc, new int[] { w });
		
		//最新版本
		qs.appendAnd();
		SearchCondition sc1 = new SearchCondition(WTPart.class,"iterationInfo.latest", SearchCondition.IS_TRUE, true);
		qs.appendWhere(sc1, new int[] { w });
		
		//关联wtpartmaser
		qs.appendAnd();
		SearchCondition s2 = new SearchCondition(WTPart.class,"masterReference.key.id", 
				WTPartMaster.class ,"thePersistInfo.theObjectIdentifier.id");
		qs.appendWhere(s2, new int[] { w,wm });
		
		//IBA属性
		if(null != ibaAttrs && ibaAttrs.size() > 0) {
			APLUtil.addIBAStringCondition(WTPart.class, qs, ibaAttrs, SearchCondition.LIKE, "", true, StringDefinition.class, StringValue.class);
		}
		
//		//对象本身属性，扩展使用
//		if(null != attrs && attrs.size() > 0) {
//			
//		}
		
		QueryResult qr = PersistenceHelper.manager.find(qs);
		logger.info("getRawMaterial sql>>:" + qs.toString());
		
		List<String> nums = new ArrayList<String>();
	    while(qr.hasMoreElements()){
	    	Object o[] = (Object[])qr.nextElement();
  	      	if(o[0] instanceof WTPart){
				WTPart part = (WTPart) o[0];
				nums.add(part.getNumber());
			}
  	    }
	    return nums;
	}
	
//	/**
//	 * 根据原材料查询成品、半成品(父--子)
//	 * @param materialNumbers
//	 * @return
//	 * @throws Exception
//	 * @author xucr
//	 * @CreateDate 2020年7月29日
//	 */
//	public String getFinishedGoodByChildren(List<String> materialNumbers) throws Exception {
//		
//		TypeDefinitionReference g1 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.FinishedGood");
//		TypeDefinitionReference g2 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.SemiFinishedGood");
//		Long [] gs = {g1.getKey().getBranchId(),g2.getKey().getBranchId()};
//		
//		Map<WTPart, List<WTPart>> resultPart = new Hashtable<WTPart, List<WTPart>>();
//		recursionWTPartUsageLinkUp(materialNumbers, gs, resultPart);// resultPart：  父项={子1, 子2, ...}
//		
//		Map<String,List<String>> resultPart2 = new HashMap<String,List<String>>();
//		recursionWTPartUsageLinkUp2(materialNumbers, gs, resultPart2);
//		
//		Map<String, Map<String,String>> result = new HashMap<String, Map<String,String>>();
//		Map<String,String> cresult = null;
//		if(null != resultPart && resultPart.size() > 0) {
//			for(Entry<WTPart, List<WTPart>> set : resultPart.entrySet()) {
//				WTPart pPart = set.getKey();
//				String pNum = pPart.getNumber();
//				String pt = getPartType(pPart);
//				List<WTPart> cParts = set.getValue();
//				for(WTPart cPart : cParts) {
//					String ct = getPartType(cPart);
//					String cNum = cPart.getNumber();
//					//{0000000164=[0000000163], 0000000163=[0000000002], 0000000004=[0000000002], 0000000133=[0000000002], 0000000132=[0000000133, 0000000164]}
//					if(resultPart2.containsKey(cNum)) {
//						List<String> childrens = resultPart2.get(cNum);
//						for(String _cNum : childrens) {
//							WTPart _cPart = PartUtil.getWTPartByNumber(_cNum);
//							String _ct = getPartType(_cPart);
//							
//							cresult = result.get(_cNum);
//							if(null == cresult) {
//								cresult = new HashMap<String, String>();
//							}
//							cresult.put(_ct, _cNum);
//							if(!cresult.containsValue(pNum)) {
//								cresult.put(pt+"_add", pNum);
//							}
//							cresult.put(ct, cNum);
//							
//							result.put(pNum, cresult);
//						}
//					}
//					
//					if(!result.containsKey(pNum)) {
//						cresult = new HashMap<String, String>();
//						cresult.put(pt, pNum);
//						cresult.put(ct, cNum);
//						result.put(pNum, cresult);
//					} else {
//						cresult = result.get(pNum);
//						cresult.put(pt, pNum);
//						cresult.put(ct, cNum);
//						result.put(pNum, cresult);
//					}
//				}
//				System.out.println("");
//			}
//		}
//		
//		return result.toString();
//	}
//	
//	/**
//	 * 子--父
//	 * @param materialNumbers
//	 * @return
//	 * @throws Exception
//	 * @author xucr
//	 * @CreateDate 2020年7月31日
//	 */
//	public String getFinishedGoodByChildren2(List<String> materialNumbers) throws Exception {
//		
//		TypeDefinitionReference g1 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.FinishedGood");
//		TypeDefinitionReference g2 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.SemiFinishedGood");
//		Long [] gs = {g1.getKey().getBranchId(),g2.getKey().getBranchId()};
//		
//		Map<WTPart, ArrayList<WTPart>> resultPart = new Hashtable<WTPart, ArrayList<WTPart>>();
//		recursionWTPartUsageLinkUp3(materialNumbers, gs, resultPart);// resultPart：  子项={父1, 父2, ...}
//		
//		Map<String,List<String>> resultPart4 = new HashMap<String,List<String>>();
//		recursionWTPartUsageLinkUp4(materialNumbers, gs, resultPart4);// resultPart：  子项={父1, 父2, ...}
//		
//		Map<String, Map<String,String>> result = new HashMap<String, Map<String,String>>();
////		List<Map<String,String>> result2 = new ArrayList<Map<String,String>>();
//		Map<String,String> cresult = null;
//		if(null != resultPart && resultPart.size() > 0) {
//			for(Entry<WTPart, ArrayList<WTPart>> set : resultPart.entrySet()) {
//				WTPart pPart = set.getKey();
//				String pNum = pPart.getNumber();
//				String pt = getPartType(pPart);
//				List<WTPart> cParts = set.getValue();
//				//{0000000133=[0000000132], 0000000163=[0000000164], 0000000002=[0000000004, 0000000133, 0000000163], 0000000164=[0000000132]}				
//				for(WTPart cPart : cParts) {
//					String ct = getPartType(cPart);
//					String cNum = cPart.getNumber();
//					
//					if(resultPart4.containsKey(cNum)) {
//						List<String> childrens = resultPart4.get(cNum);
//						for(String _cNum : childrens) {
//							WTPart _cPart = PartUtil.getWTPartByNumber(_cNum);
//							String _ct = getPartType(_cPart);
//							
//							cresult = result.get(_cNum);
//							if(null == cresult) {
//								cresult = new HashMap<String, String>();
//							}
//							cresult.put(_ct, _cNum);
//							cresult.put(pt, pNum);
//							cresult.put(ct, cNum);
//							
//							result.put(cNum, cresult);
//						}
//					}
//					
//					if(!result.containsKey(cNum)) {
//						cresult = new HashMap<String, String>();
//						cresult.put(pt, pNum);
//						cresult.put(ct, cNum);
//						result.put(cNum, cresult);
//					} else {
//						cresult = result.get(cNum);
//						cresult.put(pt, pNum);
//						cresult.put(ct, cNum);
//						result.put(cNum, cresult);
//					}
//				}
//			}
//		}
//		return result.toString();
//	}
//	
//	/**
//	 * 根据原材料查询成品、半成品
//	 * @param ibaAttrs
//	 * @param attrs
//	 * @return
//	 * @throws Exception
//	 * @author xucr
//	 * @CreateDate 2020年7月28日
//	 */
//	public String getFinishedGoodByMaterialNumber(List<String> materialNumbers) throws Exception {
//		/*	sql:
//			 select wm2.wtpartnumber,
//		        wm.wtpartnumber,
//		        w2.versionida2versioninfo || '.' || w2.iterationida2iterationinfo
//		   from pdm.wtpart          w2,
//		        pdm.wtpartmaster    wm,
//		        pdm.WTPartUsageLink wl,
//		        pdm.wtpartmaster    wm2
//		  where wl.ida3a5 = w2.ida2a2
//		    and wm.ida2a2 = wl.ida3b5
//		    and w2.ida3masterreference = wm2.ida2a2
//		    and wm.wtpartnumber in ('0000000002')
//		    and w2.latestiterationinfo = 1;
//	    */
//		
//		JSONObject rsult = new JSONObject();
//		JSONObject allData = new JSONObject();
//		rsult.put("count", 0);
//		rsult.put("data", "[]");//layui api提到，当没有数据时，要返回[]
//		rsult.put("code", "1");
//		rsult.put("msg", "您查询的数据不存在!");
//		
//		if(null != materialNumbers && materialNumbers.size() > 0) {
//			QuerySpec qs = new QuerySpec();
//		    int w2 = qs.appendClassList(WTPart.class, true);
//		    int wm = qs.appendClassList(WTPartMaster.class, false);
//		    int wm2 = qs.appendClassList(WTPartMaster.class, false);
//		    int wl = qs.appendClassList(WTPartUsageLink.class, false);
//		    qs.setAdvancedQueryEnabled(true);
//		    
//		    //仅查询成品、半成品
//			TypeDefinitionReference g1 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.FinishedGood");
//			TypeDefinitionReference g2 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.SemiFinishedGood");
//			Long [] gs = {g1.getKey().getBranchId(),g2.getKey().getBranchId()};
//			
//			SearchCondition sc = new SearchCondition(new ClassAttribute(WTPart.class, "typeDefinitionReference.key.branchId"), 
//					SearchCondition.IN, new ArrayExpression(gs));
//			qs.appendWhere(sc, new int[] { w2 });
//			
//			//最新版本
//			qs.appendAnd();
//			SearchCondition sc1 = new SearchCondition(WTPart.class,"iterationInfo.latest", SearchCondition.IS_TRUE, true);
//			qs.appendWhere(sc1, new int[] { w2 });
//			
//			//wl.ida3a5 = w2.ida2a2
//			SearchCondition s1 = new SearchCondition(WTPartUsageLink.class,"roleAObjectRef.key.id", 
//					WTPart.class, "thePersistInfo.theObjectIdentifier.id");
//			qs.appendAnd();
//			qs.appendWhere(s1, new int[] { wl,w2 });
//			
//			//wm.ida2a2 = wl.ida3b5
//			SearchCondition s2 = new SearchCondition(WTPartMaster.class,"thePersistInfo.theObjectIdentifier.id", 
//					WTPartUsageLink.class, "roleBObjectRef.key.id");
//			qs.appendAnd();
//			qs.appendWhere(s2, new int[] { wm,wl });
//			
//			//w2.ida3masterreference = wm2.ida2a2
//			SearchCondition s3 = new SearchCondition(WTPart.class,"masterReference.key.id", 
//					WTPartMaster.class, "thePersistInfo.theObjectIdentifier.id");
//			qs.appendAnd();
//			qs.appendWhere(s3, new int[] { w2,wm2 });
//			
//			//wm.wtpartnumber in ('0000000002')
//			String[] strings = new String[materialNumbers.size()];
//			SearchCondition s4 = new SearchCondition(new ClassAttribute(WTPartMaster.class,
//					WTPartMaster.NUMBER), SearchCondition.IN, new ArrayExpression(materialNumbers.toArray(strings)));
//			qs.appendAnd();
//			qs.appendWhere(s4, new int[] { wm});
//			
////			//右联
////			qs.appendAnd();
////	        SearchCondition s5 = new SearchCondition(new ClassAttribute(WTPart.class, "masterReference.key.id"),
////	                SearchCondition.EQUAL, new ClassAttribute(WTPartMaster.class, "thePersistInfo.theObjectIdentifier.id"));
////	        s5.setOuterJoin(SearchCondition.RIGHT_OUTER_JOIN);
////	        qs.appendWhere(s5, new int[]{w, wm});
//			
//			
//			//查询属性
//			//wm2.wtpartnumber, 成品、半成品编码
//			qs.appendSelectAttribute("number", wm2, false);
//			//wm.wtpartnumber, 原材料编码
//			qs.appendSelectAttribute("number", wm, false);
//			
//			//w2.versionida2versioninfo || '.' || w2.iterationida2iterationinfo 成品、半成品版本
//			qs.appendSelectAttribute("versionInfo.identifier.versionId", w2, false);
//			qs.appendSelectAttribute("iterationInfo.identifier.iterationId", w2, false);
//			
//			QueryResult qr = PersistenceHelper.manager.find(qs);
//			logger.info("getFinishedGoodByMaterialNumber sql>>:" + qs.toString());
//			
//			Map<String, String> obj = null;
//			
//			List<Object> datalist = new ArrayList<Object>();//基础数据
//			while(qr.hasMoreElements()){
//		    	Object o[] = (Object[])qr.nextElement();
//		    	WTPart cPart = (WTPart) o[0];//成品、半成品对象
//		    	String cNum = (String) o[1];//成品、半成品编码
//		    	String yNum = (String) o[2];//原材料编码
//		    	String version = (String) o[3] + "." + (String) o[4];//成品、半成品版本
//		    	
//		    	obj = new LinkedHashMap<String, String>();//有顺序的map
//		    	
//		    	WTPart ypart =PartUtil.getWTPartByNumber(yNum);
//		    	obj.put("yNum", yNum);
//		    	obj.put("yName", MaterielService.getUrlLink(ypart, false));
//		    	obj.put("yVersion", "");
//		    	obj.put("yState", ypart.getLifeCycleState().getDisplay(Locale.getDefault()));
//		    	obj.put("yView", ypart.getViewName());
//		    	
//		    	obj.put("cNum", cNum);
//		    	obj.put("cVersion", version);
//		    	obj.put("cNum", cNum);
//		    	obj.put("cName", MaterielService.getUrlLink(cPart, false));
//		    	obj.put("cView", cPart.getViewName());
//		    	obj.put("cState", cPart.getLifeCycleState().getDisplay(Locale.getDefault()));
//		    	//研发地：modulesDevelopedLand 模组研发地、panelDevelopedLand panel研发地
//		    	
//		    	datalist.add(obj);
//	  	    }
//			
//			if(datalist.size() > 0) {
//				allData.put("datalist", datalist);
//				rsult.put("count", datalist.size());
//				rsult.put("data", datalist);
//				rsult.put("code", "0");
//				rsult.put("msg", "");
//			}
//		}
//		return rsult.toString();
//	}
//	
//	/**
//	 * 递归向上查询使用关系
//	 * @param materialNumbers 参数编码
//	 * @param branchIds 查找指定类型
//	 * @param resultPart 返回结果：key: 父项part， value：子项part集合
//	 * @throws Exception
//	 * @author xucr
//	 * @CreateDate 2020年7月29日
//	 */
//	public void recursionWTPartUsageLinkUp(List<String> materialNumbers, Long [] branchIds, Map<WTPart, List<WTPart>> resultPart) throws Exception {
//		/*	sql:
//			 select wm2.wtpartnumber,
//		        wm.wtpartnumber,
//		        w2.versionida2versioninfo || '.' || w2.iterationida2iterationinfo
//		   from pdm.wtpart          w2,
//		        pdm.wtpartmaster    wm,
//		        pdm.WTPartUsageLink wl,
//		        pdm.wtpartmaster    wm2
//		  where wl.ida3a5 = w2.ida2a2
//		    and wm.ida2a2 = wl.ida3b5
//		    and w2.ida3masterreference = wm2.ida2a2
//		    and wm.wtpartnumber in ('0000000002')
//		    and w2.latestiterationinfo = 1;
//	    */
//		
//		if(null != materialNumbers && materialNumbers.size() > 0) {
//			QuerySpec qs = new QuerySpec();
//		    int w2 = qs.appendClassList(WTPart.class, true);
//		    int wm = qs.appendClassList(WTPartMaster.class, false);
//		    int wm2 = qs.appendClassList(WTPartMaster.class, false);
//		    int wl = qs.appendClassList(WTPartUsageLink.class, false);
//		    qs.setAdvancedQueryEnabled(true);
//		    
//		    //仅查询指定类型
//			SearchCondition sc = new SearchCondition(new ClassAttribute(WTPart.class, "typeDefinitionReference.key.branchId"), 
//					SearchCondition.IN, new ArrayExpression(branchIds));
//			qs.appendWhere(sc, new int[] { w2 });
//			
//			//最新版本
//			qs.appendAnd();
//			SearchCondition sc1 = new SearchCondition(WTPart.class,"iterationInfo.latest", SearchCondition.IS_TRUE, true);
//			qs.appendWhere(sc1, new int[] { w2 });
//			
//			//wl.ida3a5 = w2.ida2a2
//			SearchCondition s1 = new SearchCondition(WTPartUsageLink.class,"roleAObjectRef.key.id", 
//					WTPart.class, "thePersistInfo.theObjectIdentifier.id");
//			qs.appendAnd();
//			qs.appendWhere(s1, new int[] { wl,w2 });
//			
//			//wm.ida2a2 = wl.ida3b5
//			SearchCondition s2 = new SearchCondition(WTPartMaster.class,"thePersistInfo.theObjectIdentifier.id", 
//					WTPartUsageLink.class, "roleBObjectRef.key.id");
//			qs.appendAnd();
//			qs.appendWhere(s2, new int[] { wm,wl });
//			
//			//w2.ida3masterreference = wm2.ida2a2
//			SearchCondition s3 = new SearchCondition(WTPart.class,"masterReference.key.id", 
//					WTPartMaster.class, "thePersistInfo.theObjectIdentifier.id");
//			qs.appendAnd();
//			qs.appendWhere(s3, new int[] { w2,wm2 });
//			
//			//wm.wtpartnumber in ('0000000002')
//			String[] strings = new String[materialNumbers.size()];
//			SearchCondition s4 = new SearchCondition(new ClassAttribute(WTPartMaster.class,
//					WTPartMaster.NUMBER), SearchCondition.IN, new ArrayExpression(materialNumbers.toArray(strings)));
//			qs.appendAnd();
//			qs.appendWhere(s4, new int[] { wm});
//			
//			
////			//查询属性
//			//wm2.wtpartnumber, 父项
//			qs.appendSelectAttribute("number", wm2, false);
//			//wm.wtpartnumber, 子项
//			qs.appendSelectAttribute("number", wm, false);
//			
//			QueryResult qr = PersistenceHelper.manager.find(qs);
//			logger.info("getFinishedGoodByMaterialNumber sql>>:" + qs.toString());
//			
//			List<WTPart> parts = null;//子项集合
//			List<String> paramsNums = new ArrayList<String>();
//			while(qr.hasMoreElements()){
//		    	Object o[] = (Object[])qr.nextElement();
//		    	WTPart cPart = (WTPart) o[0];//父项
//		    	String cNum = cPart.getNumber();
//		    	String yNum = (String) o[2];
//		    	WTPart ypart =PartUtil.getWTPartByNumber(yNum);//子项
//		    	
//		    	if(!paramsNums.contains(cNum)) {
//		    		paramsNums.add(cNum);
//		    	}
//		    	
//		    	if(!resultPart.containsKey(cPart)) {
//		    		parts = new ArrayList<WTPart>();
//		    		parts.add(ypart);
//		    		
//		    		resultPart.put(cPart, parts);
//		    	} else {
//		    		parts = resultPart.get(cPart);
//		    		//由于此递归没有做最新大版本的查询，有可能会有多条记录，这里再去重
//		    		if(!parts.contains(ypart)) {
//		    			parts.add(ypart);
//			    		resultPart.put(cPart, parts);
//		    		}
//		    	}
//	  	    }
//			recursionWTPartUsageLinkUp(paramsNums, branchIds, resultPart);
//		}
//	}
//	
//	/**
//	 * 递归向上查询使用关系
//	 * @param materialNumbers 参数编码
//	 * @param branchIds 查找指定类型
//	 * @param resultPart 返回结果：key: 父项part， value：子项part集合
//	 * @throws Exception
//	 * @author xucr
//	 * @CreateDate 2020年7月29日
//	 */
//	public void recursionWTPartUsageLinkUp2(List<String> materialNumbers, Long [] branchIds, Map<String, List<String>> resultPart) throws Exception {
//		/*	sql:
//			 select wm2.wtpartnumber,
//		        wm.wtpartnumber,
//		        w2.versionida2versioninfo || '.' || w2.iterationida2iterationinfo
//		   from pdm.wtpart          w2,
//		        pdm.wtpartmaster    wm,
//		        pdm.WTPartUsageLink wl,
//		        pdm.wtpartmaster    wm2
//		  where wl.ida3a5 = w2.ida2a2
//		    and wm.ida2a2 = wl.ida3b5
//		    and w2.ida3masterreference = wm2.ida2a2
//		    and wm.wtpartnumber in ('0000000002')
//		    and w2.latestiterationinfo = 1;
//	    */
//		
//		if(null != materialNumbers && materialNumbers.size() > 0) {
//			QuerySpec qs = new QuerySpec();
//		    int w2 = qs.appendClassList(WTPart.class, true);
//		    int wm = qs.appendClassList(WTPartMaster.class, false);
//		    int wm2 = qs.appendClassList(WTPartMaster.class, false);
//		    int wl = qs.appendClassList(WTPartUsageLink.class, false);
//		    qs.setAdvancedQueryEnabled(true);
//		    
//		    //仅查询指定类型
//			SearchCondition sc = new SearchCondition(new ClassAttribute(WTPart.class, "typeDefinitionReference.key.branchId"), 
//					SearchCondition.IN, new ArrayExpression(branchIds));
//			qs.appendWhere(sc, new int[] { w2 });
//			
//			//最新版本
//			qs.appendAnd();
//			SearchCondition sc1 = new SearchCondition(WTPart.class,"iterationInfo.latest", SearchCondition.IS_TRUE, true);
//			qs.appendWhere(sc1, new int[] { w2 });
//			
//			//wl.ida3a5 = w2.ida2a2
//			SearchCondition s1 = new SearchCondition(WTPartUsageLink.class,"roleAObjectRef.key.id", 
//					WTPart.class, "thePersistInfo.theObjectIdentifier.id");
//			qs.appendAnd();
//			qs.appendWhere(s1, new int[] { wl,w2 });
//			
//			//wm.ida2a2 = wl.ida3b5
//			SearchCondition s2 = new SearchCondition(WTPartMaster.class,"thePersistInfo.theObjectIdentifier.id", 
//					WTPartUsageLink.class, "roleBObjectRef.key.id");
//			qs.appendAnd();
//			qs.appendWhere(s2, new int[] { wm,wl });
//			
//			//w2.ida3masterreference = wm2.ida2a2
//			SearchCondition s3 = new SearchCondition(WTPart.class,"masterReference.key.id", 
//					WTPartMaster.class, "thePersistInfo.theObjectIdentifier.id");
//			qs.appendAnd();
//			qs.appendWhere(s3, new int[] { w2,wm2 });
//			
//			//wm.wtpartnumber in ('0000000002')
//			String[] strings = new String[materialNumbers.size()];
//			SearchCondition s4 = new SearchCondition(new ClassAttribute(WTPartMaster.class,
//					WTPartMaster.NUMBER), SearchCondition.IN, new ArrayExpression(materialNumbers.toArray(strings)));
//			qs.appendAnd();
//			qs.appendWhere(s4, new int[] { wm});
//			
//			
////			//查询属性
//			//wm2.wtpartnumber, 父项
//			qs.appendSelectAttribute("number", wm2, false);
//			//wm.wtpartnumber, 子项
//			qs.appendSelectAttribute("number", wm, false);
//			
//			QueryResult qr = PersistenceHelper.manager.find(qs);
//			logger.info("getFinishedGoodByMaterialNumber sql>>:" + qs.toString());
//			
//			List<String> parts = null;//子项集合
//			List<String> paramsNums = new ArrayList<String>();
//			while(qr.hasMoreElements()){
//		    	Object o[] = (Object[])qr.nextElement();
//		    	WTPart cPart = (WTPart) o[0];//父项
//		    	String cNum = cPart.getNumber();//父项id
//		    	
//		    	String yNum = (String) o[2];//子项
//		    	WTPart yPart = PartUtil.getWTPartByNumber(yNum);//子项
//		    	
//		    	if(!paramsNums.contains(cNum)) {
//		    		paramsNums.add(cNum);
//		    	}
//		    	
//		    	if(!resultPart.containsKey(cNum)) {
//		    		parts = new ArrayList<String>();
//		    		parts.add(yNum);
//		    		
//		    		resultPart.put(cNum, parts);
//		    	} else {
//		    		parts = resultPart.get(cNum);
//		    		//由于此递归没有做最新大版本的查询，有可能会有多条记录，这里再去重
//		    		if(!parts.contains(yNum)) {
//		    			parts.add(yNum);
//			    		resultPart.put(cNum, parts);
//		    		}
//		    	}
//	  	    }
//			recursionWTPartUsageLinkUp2(paramsNums, branchIds, resultPart);
//		}
//	}
	
	/**
	 * 递归向上查询使用关系
	 * @param materialNumbers 参数编码
	 * @param branchIds 查找指定类型
	 * @param resultPart 返回结果：key: 父项part， value：子项part集合
	 * @throws Exception
	 * @author xucr
	 * @CreateDate 2020年7月29日
	 */
	public void recursionWTPartUsageLinkUp3(List<String> materialNumbers, Long [] branchIds, Map<WTPart, ArrayList<WTPart>> resultPart) throws Exception {
		/*	sql:
			 select wm2.wtpartnumber,
		        wm.wtpartnumber,
		        w2.versionida2versioninfo || '.' || w2.iterationida2iterationinfo
		   from pdm.wtpart          w2,
		        pdm.wtpartmaster    wm,
		        pdm.WTPartUsageLink wl,
		        pdm.wtpartmaster    wm2
		  where wl.ida3a5 = w2.ida2a2
		    and wm.ida2a2 = wl.ida3b5
		    and w2.ida3masterreference = wm2.ida2a2
		    and wm.wtpartnumber in ('0000000002')
		    and w2.latestiterationinfo = 1;
	    */
		
		if(null != materialNumbers && materialNumbers.size() > 0) {
			QuerySpec qs = new QuerySpec();
		    int w2 = qs.appendClassList(WTPart.class, true);
		    int wm = qs.appendClassList(WTPartMaster.class, false);
		    int wm2 = qs.appendClassList(WTPartMaster.class, false);
		    int wl = qs.appendClassList(WTPartUsageLink.class, false);
		    qs.setAdvancedQueryEnabled(true);
		    
		    //仅查询指定类型
			SearchCondition sc = new SearchCondition(new ClassAttribute(WTPart.class, "typeDefinitionReference.key.branchId"), 
					SearchCondition.IN, new ArrayExpression(branchIds));
			qs.appendWhere(sc, new int[] { w2 });
			
			//最新小版本
			qs.appendAnd();
			SearchCondition sc1 = new SearchCondition(WTPart.class,"iterationInfo.latest", SearchCondition.IS_TRUE, true);
			qs.appendWhere(sc1, new int[] { w2 });
			
			//最新大版本
			addSearchConditionLasterVersion(qs, WTPart.class,null);
			
			//wl.ida3a5 = w2.ida2a2
			SearchCondition s1 = new SearchCondition(WTPartUsageLink.class,"roleAObjectRef.key.id", 
					WTPart.class, "thePersistInfo.theObjectIdentifier.id");
			qs.appendAnd();
			qs.appendWhere(s1, new int[] { wl,w2 });
			
			//wm.ida2a2 = wl.ida3b5
			SearchCondition s2 = new SearchCondition(WTPartMaster.class,"thePersistInfo.theObjectIdentifier.id", 
					WTPartUsageLink.class, "roleBObjectRef.key.id");
			qs.appendAnd();
			qs.appendWhere(s2, new int[] { wm,wl });
			
			//w2.ida3masterreference = wm2.ida2a2
			SearchCondition s3 = new SearchCondition(WTPart.class,"masterReference.key.id", 
					WTPartMaster.class, "thePersistInfo.theObjectIdentifier.id");
			qs.appendAnd();
			qs.appendWhere(s3, new int[] { w2,wm2 });
			
			//wm.wtpartnumber in ('0000000002')
			String[] strings = new String[materialNumbers.size()];
			SearchCondition s4 = new SearchCondition(new ClassAttribute(WTPartMaster.class,
					WTPartMaster.NUMBER), SearchCondition.IN, new ArrayExpression(materialNumbers.toArray(strings)));
			qs.appendAnd();
			qs.appendWhere(s4, new int[] { wm});
			
			
//			//查询属性
			//wm2.wtpartnumber, 父项
			qs.appendSelectAttribute("number", wm2, false);
			//wm.wtpartnumber, 子项
			qs.appendSelectAttribute("number", wm, false);
			
			QueryResult qr = PersistenceHelper.manager.find(qs);
			logger.info("getFinishedGoodByMaterialNumber sql>>:" + qs.toString());
			
			ArrayList<WTPart> parts = null;//子项集合
			List<String> paramsNums = new ArrayList<String>();
			//取最新的
			while(qr.hasMoreElements()){
		    	Object o[] = (Object[])qr.nextElement();
		    	WTPart cPart = (WTPart) o[0];//父项
		    	String cNum = cPart.getNumber();
		    	String yNum = (String) o[2];
		    	WTPart yPart =PartUtil.getWTPartByNumber(yNum);//子项
		    	
		    	if(!paramsNums.contains(cNum)) {
		    		paramsNums.add(cNum);
		    	}
		    	
		    	if(!resultPart.containsKey(yPart)) {
		    		parts = new ArrayList<WTPart>();
		    		parts.add(cPart);
		    		
		    		resultPart.put(yPart, parts);
		    	} else {
		    		parts = resultPart.get(yPart);
		    		//由于此递归没有做最新大版本的查询，有可能会有多条记录，这里再去重
		    		if(!parts.contains(cPart)) {
		    			parts.add(cPart);
			    		resultPart.put(yPart, parts);
		    		}
		    	}
	  	    }
			recursionWTPartUsageLinkUp3(paramsNums, branchIds, resultPart);
		}
	}
	
	/**
	 * 最新大版本
	 * @param parentQS 上层QuerySpec
	 * @param clazz 指定的对象 WTDocument.class or WTPart.class
	 * @param conditions 在过滤最新大版本时添加额外的（clazz）条件，例如：设计视图（或者某个制造视图)或者其它对象上的属性
	 * @return 
	 * @author xucr
	 * @CreateDate 2020年8月4日
	 */
	public static QuerySpec addSearchConditionLasterVersion(QuerySpec parentQS, Class clazz,
			Collection<SearchCondition> conditions) {
		try {
			int index = parentQS.getFromClause().getPosition(clazz); // 主查询位置
			parentQS.setAdvancedQueryEnabled(true);
			String alias = parentQS.getFromClause().getAliasAt(index);// 主查询别名
			QuerySpec subQuery = new QuerySpec();
			subQuery.getFromClause().setAliasPrefix("B");
			int index2 = subQuery.appendClassList(clazz, false);
			String alias2 = subQuery.getFromClause().getAliasAt(index2);
			TableColumn masterid = new TableColumn(alias, "Ida3masterreference");
			TableColumn masterid2 = new TableColumn(alias2, "Ida3masterreference");
			SearchCondition where1 = new SearchCondition(masterid, SearchCondition.EQUAL, masterid2);
			if (subQuery.getConditionCount() > 0) {
				subQuery.appendAnd();
			}
			subQuery.appendWhere(where1, new int[] { index, index2 });

			// conditions 添加额外的查询条件
			if (conditions != null && conditions.size() > 0) {
				for (SearchCondition condition : conditions) {
					if (subQuery.getConditionCount() > 0) {
						subQuery.appendAnd();
					}
					subQuery.appendWhere(condition, new int[] { index2 });
				}
			}
			TableColumn versionColumn = new TableColumn(alias2, "versionSortIdA2versionInfo");
			SQLFunction sf0 = SQLFunction.newSQLFunction(SQLFunction.MAXIMUM);
			sf0.setArgumentAt(versionColumn, 0);
			sf0.setColumnAlias("versionSortIdA2versionInfo");
			subQuery.appendSelect(sf0, false);
			SubSelectExpression sse = new SubSelectExpression(subQuery);
			ClassAttribute mca = new ClassAttribute(clazz, "versionInfo.identifier.versionSortId");// versionSortIdA2versionInfo
			SearchCondition sc = new SearchCondition(mca, SearchCondition.IN, sse);
			if (parentQS.getConditionCount() > 0) {
				parentQS.appendAnd();
			}
			parentQS.appendWhere(sc, new int[] { index });
		} catch (QueryException e) {
			e.printStackTrace();
		} catch (WTPropertyVetoException e) {
			e.printStackTrace();
		}
		return parentQS;
	}
	
//	public void recursionWTPartUsageLinkUp4(List<String> materialNumbers, Long [] branchIds, Map<String, List<String>> resultPart) throws Exception {
//		/*	sql:
//			 select wm2.wtpartnumber,
//		        wm.wtpartnumber,
//		        w2.versionida2versioninfo || '.' || w2.iterationida2iterationinfo
//		   from pdm.wtpart          w2,
//		        pdm.wtpartmaster    wm,
//		        pdm.WTPartUsageLink wl,
//		        pdm.wtpartmaster    wm2
//		  where wl.ida3a5 = w2.ida2a2
//		    and wm.ida2a2 = wl.ida3b5
//		    and w2.ida3masterreference = wm2.ida2a2
//		    and wm.wtpartnumber in ('0000000002')
//		    and w2.latestiterationinfo = 1;
//	    */
//		
//		if(null != materialNumbers && materialNumbers.size() > 0) {
//			QuerySpec qs = new QuerySpec();
//		    int w2 = qs.appendClassList(WTPart.class, true);
//		    int wm = qs.appendClassList(WTPartMaster.class, false);
//		    int wm2 = qs.appendClassList(WTPartMaster.class, false);
//		    int wl = qs.appendClassList(WTPartUsageLink.class, false);
//		    qs.setAdvancedQueryEnabled(true);
//		    
//		    //仅查询指定类型
//			SearchCondition sc = new SearchCondition(new ClassAttribute(WTPart.class, "typeDefinitionReference.key.branchId"), 
//					SearchCondition.IN, new ArrayExpression(branchIds));
//			qs.appendWhere(sc, new int[] { w2 });
//			
//			//最新版本
//			qs.appendAnd();
//			SearchCondition sc1 = new SearchCondition(WTPart.class,"iterationInfo.latest", SearchCondition.IS_TRUE, true);
//			qs.appendWhere(sc1, new int[] { w2 });
//			
//			//wl.ida3a5 = w2.ida2a2
//			SearchCondition s1 = new SearchCondition(WTPartUsageLink.class,"roleAObjectRef.key.id", 
//					WTPart.class, "thePersistInfo.theObjectIdentifier.id");
//			qs.appendAnd();
//			qs.appendWhere(s1, new int[] { wl,w2 });
//			
//			//wm.ida2a2 = wl.ida3b5
//			SearchCondition s2 = new SearchCondition(WTPartMaster.class,"thePersistInfo.theObjectIdentifier.id", 
//					WTPartUsageLink.class, "roleBObjectRef.key.id");
//			qs.appendAnd();
//			qs.appendWhere(s2, new int[] { wm,wl });
//			
//			//w2.ida3masterreference = wm2.ida2a2
//			SearchCondition s3 = new SearchCondition(WTPart.class,"masterReference.key.id", 
//					WTPartMaster.class, "thePersistInfo.theObjectIdentifier.id");
//			qs.appendAnd();
//			qs.appendWhere(s3, new int[] { w2,wm2 });
//			
//			//wm.wtpartnumber in ('0000000002')
//			String[] strings = new String[materialNumbers.size()];
//			SearchCondition s4 = new SearchCondition(new ClassAttribute(WTPartMaster.class,
//					WTPartMaster.NUMBER), SearchCondition.IN, new ArrayExpression(materialNumbers.toArray(strings)));
//			qs.appendAnd();
//			qs.appendWhere(s4, new int[] { wm});
//			
//			
////			//查询属性
//			//wm2.wtpartnumber, 父项
//			qs.appendSelectAttribute("number", wm2, false);
//			//wm.wtpartnumber, 子项
//			qs.appendSelectAttribute("number", wm, false);
//			
//			QueryResult qr = PersistenceHelper.manager.find(qs);
//			logger.info("getFinishedGoodByMaterialNumber sql>>:" + qs.toString());
//			
//			List<String> parts = null;//子项集合
//			List<String> paramsNums = new ArrayList<String>();
//			while(qr.hasMoreElements()){
//		    	Object o[] = (Object[])qr.nextElement();
//		    	WTPart cPart = (WTPart) o[0];//父项
//		    	String cNum = cPart.getNumber();
//		    	String yNum = (String) o[2];
//		    	WTPart yPart =PartUtil.getWTPartByNumber(yNum);//子项
//		    	
//		    	if(!paramsNums.contains(cNum)) {
//		    		paramsNums.add(cNum);
//		    	}
//		    	
//		    	if(!resultPart.containsKey(yNum)) {
//		    		parts = new ArrayList<String>();
//		    		parts.add(cNum);
//		    		
//		    		resultPart.put(yNum, parts);
//		    	} else {
//		    		parts = resultPart.get(yNum);
//		    		//由于此递归没有做最新大版本的查询，有可能会有多条记录，这里再去重
//		    		if(!parts.contains(cNum)) {
//		    			parts.add(cNum);
//			    		resultPart.put(yNum, parts);
//		    		}
//		    	}
//	  	    }
//			recursionWTPartUsageLinkUp4(paramsNums, branchIds, resultPart);
//		}
//	}
//	
//	private String getPartType(WTPart part) throws RemoteException, WTException {
//		String softtype = GenericUtil.getTypeId(part);
//		String type = "";
//		if(softtype.indexOf("cn.tianma.FinishedGood") != -1) {//成品
//			type = "c";
//		} else if(softtype.indexOf("cn.tianma.SemiFinishedGood") != -1) {//半成品
//			type = "bc";
//		} else if(softtype.indexOf("cn.tianma.RawMaterial") != -1) {//原材料
//			type = "y";
//		}
//		return type;
//	}
	
	/**
	 * 反查成品，重写MaterialReverseService.searhMaterialPart()
	 * @param number
	 * @return
	 * @author xucr
	 * @throws Exception 
	 * @CreateDate 2020年7月29日
	 */
	public String searhMaterialPart(List<String> numbers) throws Exception {
		JSONObject obj = new JSONObject();
		JSONArray array = new JSONArray();
		
		obj.put("count", 0);
		obj.put("data", "[]");//layui api提到，当没有数据时，要返回[]
		obj.put("code", "1");
		obj.put("msg", "您查询的数据不存在!");
		
		if(null != numbers && numbers.size() > 0) {
			// 获取物料的全视图集合
			List<WTPart> list = getAllLatestVersionPart(numbers);

			// 存放物料对应的父层 key - value集合 或半成品与成品对应的key - value集合 ,用于展示
			TypeDefinitionReference g1 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.FinishedGood");
			TypeDefinitionReference g2 = ClientTypedUtility.getTypeDefinitionReference("cn.tianma.SemiFinishedGood");
			Long [] gs = {g1.getKey().getBranchId(),g2.getKey().getBranchId()};
			
			Map<WTPart, ArrayList<WTPart>> firstLevolmap = new Hashtable<WTPart, ArrayList<WTPart>>();
			recursionWTPartUsageLinkUp3(numbers, gs, firstLevolmap);// resultPart：  子项={父1, 父2, ...}
			
			logger.info("=======firstLevolmap:" + firstLevolmap.toString());
			logger.info("=======list:" + list.size());
			logger.info("=======list:" + list.toString());
				
			for (WTPart part1 : list) {
				// 取物料的半成品或成品集合
				ArrayList<WTPart> parentslist = firstLevolmap.get(part1);
				logger.info("=======part1:" + part1.getNumber() + "==" + part1.getViewName() + "====version:"
						+ VersionControlHelper.getIterationDisplayIdentifier(part1).toString());
				if (parentslist != null) {
					for (WTPart showpart : parentslist) {
						String softtype = GenericUtil.getTypeId(showpart);
						String state = showpart.getState().getState().getDisplay(Locale.CHINA);
						if("废弃".equals(state)){//OBSOLESCENCE
							continue;
						}
						// 如果是成品 直接写值
						if (softtype.indexOf("cn.tianma.FinishedGood") != -1) {
							JSONObject object = getFinishedGoodAttrs(part1, showpart);
							array.put(object);
							logger.info(part1.getNumber() + "====searhMaterialPart  obj 111:" + object.toString());
						} else {
							// 半成品 查找是否存在对应的成品
							ArrayList<WTPart> finishedlist = firstLevolmap.get(showpart);
							
							if (finishedlist != null && finishedlist.size() != 0) {
								//是否存在成品
								boolean flag = false;
								//是否已添加
								for(WTPart halfpart : finishedlist){
									String halfsofttype = GenericUtil.getTypeId(halfpart);
									if (halfsofttype.indexOf("cn.tianma.FinishedGood") != -1) {
										flag = true;
										break;
									}
								}
								JSONObject object = null;
								for (WTPart halfpart : finishedlist) {
									String halfsofttype = GenericUtil.getTypeId(halfpart);
									String halfstate = halfpart.getState().getState().getDisplay(Locale.CHINA);
									if("废弃".equals(halfstate)){
										continue;
									}
									// 半成品存在相应的成品时
									if (halfsofttype.indexOf("cn.tianma.FinishedGood") != -1) {
										logger.info("==========2222222222222222===="+halfpart.getNumber()+"--"+halfpart.getViewName()+"==="+parentslist.contains(halfpart));
										object = getAttrs(part1, halfpart, showpart, parentslist);
										array.put(object);
									} else {
										// 成品属性
										if(!flag){
											object = getSemiFinishedGoodAttrs(part1, showpart);
											array.put(object);
											flag = true;
										}
										//继续往根节点取成品
										array = FinishedGoodArray(firstLevolmap,array,halfpart,part1);
									}
									logger.info("====searhMaterialPart  obj 222:" + object.toString());
								}
							} else {
								logger.info("===showpart number:"+showpart.getNumber()+"--view:"+showpart.getViewName()+"--type:"+softtype);

								// 半成品未找到相应的成品
								JSONObject object = getSemiFinishedGoodAttrs(part1, showpart);
								array.put(object);

								logger.info("====searhMaterialPart  obj 333:" + object.toString());
							}
						}
					}
				}
			}
				
			obj.put("count", array.length());
			obj.put("data", array);
			obj.put("code", "0");
			obj.put("msg", "");
			logger.info("====MaterialReverseService.searhMaterialPart:" + obj.toString());	
		}
		return obj.toString();
	}
	
	/**
	 * 查询所有版本
	 * @param numbers
	 * @return
	 * @throws Exception
	 * @author xucr
	 * @CreateDate 2020年7月30日
	 */
	public static List<WTPart> getAllLatestVersionPart(List<String> numbers) throws Exception {
		List<WTPart> list = new ArrayList<WTPart>();
		WTPart part = null;
		
		String[] strings = new String[numbers.size()];
		
		QuerySpec qs = new QuerySpec(WTPart.class);
		SearchCondition sc = new SearchCondition(new ClassAttribute(WTPart.class,
				WTPart.NUMBER), SearchCondition.IN, new ArrayExpression(numbers.toArray(strings)));
		qs.appendWhere(sc, new int[] { 0 });
		qs.appendAnd();
		
		SearchCondition sc1 = new SearchCondition(WTPart.class,"iterationInfo.latest", SearchCondition.IS_TRUE, true);
		qs.appendWhere(sc1, new int[] { 0 });
		
		qs.appendOrderBy(WTPart.class, "thePersistInfo.createStamp", true);
		QueryResult qr2 = PersistenceHelper.manager.find(qs);
		while (qr2.hasMoreElements()) {
			part = (WTPart) qr2.nextElement();
			wt.vc.VersionIdentifier vi = wt.vc.VersionControlHelper.nextVersionId(part);
			String v = vi.getValue();
			WTPart p = MaterialReverseService.getPart(part.getNumber(), v, part.getView().getName());
			if (null != p) {
				continue;
			}
			if (!list.contains(part)) {
				list.add(part);
			}
		}
		return list;
	}
	
	/**
	 * 返回成品属性
	 * @param part1
	 * @param prentPart
	 * @return
	 * @throws JSONException
	 * @author xucr
	 * @throws WTException 
	 * @throws IOException 
	 * @CreateDate 2020年7月30日
	 */
	private JSONObject getFinishedGoodAttrs(WTPart part1, WTPart prentPart) throws JSONException, IOException, WTException {
		/**
		 * 原材料上面直接是成品时：
		 * 没有半成品属性
		 * */
		JSONObject object = new JSONObject();
		object.put("yNum", part1.getNumber());
		object.put("yName", MaterielService.getUrlLink(part1, false));
		object.put("yView", part1.getViewName());
		object.put("yState", part1.getState().getState().getDisplay(Locale.CHINA));
		object.put("yVersion",VersionControlHelper.getIterationDisplayIdentifier(part1).toString());
		// 成品属性
		object.put("cNum", prentPart.getNumber());
		object.put("cName", MaterielService.getUrlLink(prentPart, false));
		object.put("cVersion",VersionControlHelper.getIterationDisplayIdentifier(prentPart).toString());
		object.put("cView", prentPart.getViewName());
		object.put("cState", prentPart.getState().getState().getDisplay(Locale.CHINA));

		// 半成品属性
		object.put("bcName", "");
		object.put("bcNum", "");
		object.put("bcVersion", "");
		object.put("bcView", "");
		object.put("bcState", "");
		
		return object;
	}
	
	/**
	 * 返回半成品属性
	 * @param part1
	 * @param prentPart
	 * @return
	 * @throws JSONException
	 * @author xucr
	 * @throws WTException 
	 * @throws IOException 
	 * @CreateDate 2020年7月30日
	 */
	private JSONObject getSemiFinishedGoodAttrs(WTPart part1, WTPart prentPart) throws JSONException, IOException, WTException {
		/**
		 * 原材料上面有半成品，半成品上面无成品时：
		 * 没有成品属性
		 * */
		JSONObject object = new JSONObject();
		object.put("yNum", part1.getNumber());
		object.put("yName", MaterielService.getUrlLink(part1, false));
		object.put("yView", part1.getViewName());
		object.put("yState", part1.getState().getState().getDisplay(Locale.CHINA));
		object.put("yVersion",VersionControlHelper.getIterationDisplayIdentifier(part1).toString());

		// 成品属性
		object.put("cNum", "");
		object.put("cName", "");
		object.put("cVersion", "");
		object.put("cView", "");
		object.put("cState", "");

		// 半成品属性
		object.put("bcNum", prentPart.getNumber());
		object.put("bcName", MaterielService.getUrlLink(prentPart, false));
		object.put("bcVersion", VersionControlHelper.getIterationDisplayIdentifier(prentPart).toString());
		object.put("bcView", prentPart.getViewName());
		object.put("bcState", prentPart.getState().getState().getDisplay(Locale.CHINA));
		
		return object;
	}
	
	private JSONObject getAttrs(WTPart part1, WTPart fPart, WTPart sfPart, ArrayList<WTPart> parentslist) throws JSONException, WTException, IOException {
		/**
		 * 原材料上面有半成品，半成品上面有成品时：
		 * 原材料--成品--半成品  ：均有属性
		 * */
		String halfsofttype = GenericUtil.getTypeId(fPart);
		JSONObject object = new JSONObject();
		object.put("yNum", part1.getNumber());
		object.put("yName", MaterielService.getUrlLink(part1, false));
		object.put("yView", part1.getViewName());
		object.put("yState", part1.getState().getState().getDisplay(Locale.CHINA));
		object.put("yVersion",VersionControlHelper.getIterationDisplayIdentifier(part1).toString());
		logger.info("===fPart number:"+fPart.getNumber()+"--view:"+fPart.getViewName()+"--type:"+halfsofttype);
		// 半成品存在相应的成品时
		logger.info("==========2222222222222222===="+fPart.getNumber()+"--"+fPart.getViewName()+"==="+parentslist.contains(fPart));
		if(!parentslist.contains(fPart)){
			// 成品属性
			object.put("cNum", fPart.getNumber());
			object.put("cName", MaterielService.getUrlLink(fPart, false));
			object.put("cVersion", VersionControlHelper.getIterationDisplayIdentifier(fPart).toString());
			object.put("cView", fPart.getViewName());
			object.put("cState", fPart.getState().getState().getDisplay(Locale.CHINA));
			// 半成品属性
			object.put("bcNum", sfPart.getNumber());
			object.put("bcName", MaterielService.getUrlLink(sfPart, false));
			object.put("bcVersion", VersionControlHelper.getIterationDisplayIdentifier(sfPart).toString());
			object.put("bcView", sfPart.getViewName());
			object.put("bcState", sfPart.getState().getState().getDisplay(Locale.CHINA));
		}
		return object;
	}
	
	/**
	 * 
	 * @param firstLevolmap
	 * @param array
	 * @param part
	 * @param basicpart
	 * @return
	 * @throws Exception
	 * @author xucr
	 * @CreateDate 2020年8月3日
	 */
	public static JSONArray FinishedGoodArray(Map<WTPart, ArrayList<WTPart>> firstLevolmap,
			JSONArray array,WTPart part,WTPart basicpart) throws Exception{
		
		/**
		 * 通过物料A查找非直接关系的成品D
		 * 如：A-->B-->C-->D
		 * 通过A找到半成品B 再间接找到成品D  B、D不存在直接关系
		 * */
		if(firstLevolmap.containsKey(part)){
			ArrayList<WTPart> finishedlist = firstLevolmap.get(part);
			for (WTPart halfpart : finishedlist) {
				//类型
				String halfsofttype = GenericUtil.getTypeId(halfpart);
				String halfstate = halfpart.getState().getState().getDisplay(Locale.CHINA);
				if("废弃".equals(halfstate)){
					continue;
				}
				JSONObject object = new JSONObject();

				// 半成品存在相应的成品时
				object.put("yNum", basicpart.getNumber());
				object.put("yName", MaterielService.getUrlLink(basicpart, false));
				object.put("yView", basicpart.getViewName());
				object.put("yState", basicpart.getState().getState().getDisplay(Locale.CHINA));
				object.put("yVersion",VersionControlHelper.getIterationDisplayIdentifier(basicpart).toString());
				
				// 成品属性
				if (halfsofttype.indexOf("cn.tianma.FinishedGood") != -1) {
//					logger.info("==========333333333333333333===="+halfpart.getNumber()+"--"+halfpart.getViewName()+"==="+finishedlist.contains(halfpart));
					object.put("cNum", halfpart.getNumber());
					object.put("cVersion", VersionControlHelper.getIterationDisplayIdentifier(halfpart).toString());
					object.put("cView", halfpart.getViewName());
					object.put("cState", halfpart.getState().getState().getDisplay(Locale.CHINA));

					// 半成品属性
					object.put("bcNum", "");
					object.put("bcVersion", "");
					object.put("bcView", "");
					object.put("bcState", "");

					array.put(object);
				} else {
					array = FinishedGoodArray(firstLevolmap,array,halfpart,basicpart);
				} 
			}
		}
		
		return array;
	}
	
	
//	public static List getParents(WTPart child,boolean onlyNumber) {
//		if (child == null)
//			return null;
//		List aParents = new ArrayList();
//		try {
////			QueryResult qr = WTPartHelper.service
////					.getUsedByWTParts((WTPartMaster) child.getMasterReference()
////							.getObject());
//			QueryResult qr = WTPartHelper.service
//					.getUsedByWTParts((WTPartMaster) child.getMasterReference()
//							.getObject(), false);
//			while (qr.hasMoreElements()) {
//				if(!onlyNumber)
//					aParents.add((WTPart) qr.nextElement());
//				else
//					aParents.add(((WTPart) qr.nextElement()).getNumber());
//			}
//		} catch (Exception e) {
//			// TODO: handle exception
//			e.printStackTrace();
//		}
//		return aParents;
//	}
	
	/**
	 * 获取父项
	 * @param child
	 * @param onlyNumber
	 * @param branchIds
	 * @param parents
	 * @throws WTException
	 * @author xucr
	 * @CreateDate 2020年8月3日
	 */
	@SuppressWarnings({ "unchecked"})
	public static <E> void getParents(WTPart child,boolean onlyNumber, Long [] branchIds, Map<String,List<E>> parents) throws WTException {
		QuerySpec queryspec = new QuerySpec(WTPart.class, WTPartUsageLink.class);
		queryspec.appendWhere(VersionControlHelper.getSearchCondition(WTPart.class, true), new int[] { 0, 1 });
		queryspec.appendAnd();
		SearchCondition sc = new SearchCondition(
				new ClassAttribute(WTPart.class, "typeDefinitionReference.key.branchId"), 
				SearchCondition.IN, 
				new ArrayExpression(branchIds));
		queryspec.appendWhere(sc, new int[] { 0 });
		
		QueryResult qr = PersistenceHelper.manager.navigate(child.getMaster(), "usedBy", queryspec, true);
		LatestConfigSpec lcs = new LatestConfigSpec();
		qr = lcs.process(qr);
		List<E> parts = null;
		String childNum = child.getNumber();
		while (qr.hasMoreElements()) {
			WTPart parentPart = (WTPart) qr.nextElement();
			String num = parentPart.getNumber();
			
		    if(!parents.containsKey(childNum)) {
	    		parts = new ArrayList<>();
	    	} else {
	    		parts = parents.get(childNum);
	    	}
		    if(onlyNumber) {
    			parts.add((E) num);
    		} else {
    			parts.add((E) parentPart);
    		}
    		parents.put(childNum, parts);
			
			getParents(parentPart, onlyNumber, branchIds, parents);
		}
	}
	
	
}
